I am new to VCV Rack development, though not a noob programmer
I have created an LedDisplayTextField in my module. I want to display some info in that text box. I also want to grab its content when the user changes it.
I am trying to wrap my head around how the UI elements interact with the module code. From what I can gather, by looking at other people’s code, it seems to revolve around dataToJson and dataFromJson calls? Am I correct? How do I attach the text field to json? Will the module get an event when the textfield’s value change? How do I set it? By inheriting LedDisplayTextField, and override the draw call?
If somebody can point me to something that works along this line, would be greatly appreciated.
Is there documentation on how the param system works? I looked through the api doc, can’t seem to find any.
Is there a place that I can find what has been declared for my modules? Looking through other people’s code, I often find myself going, wait, where did that variable come from?
Lastly, I like to use print statements to do some debugging, is there a convention or a debug logging call that I should use? Where will the debug info go? i.e. the log file?
data to and from json is saved with the patch. GUI parameters such as those named in enum ParamIds will always be saved regardless.
Depends on what your text field is doing. You could use a pointer and set conditions based on this number to the address of a number in your dsp. The pointer could be sent to/from json. For example if the text field is outputting different strings you could store these in an array in the draw function and just send/receive the index position to/from json instead of a full string.
DEBUG(""); depending on your platform will output to the console in msys2. But using this in process() will output many times a sample, so you could set a condition to only output once like: on a button press use a dsp::SchmittTrigger to print once, if you really need to use it in process without this protection you could also use dsp::ClockDivider to limit the amount of time DEBUG processes so it doesn’t use too much CPU.
Yes, I figured that I was over complicating it. Your solution would be the most common approach.
But I can’t seem to find any documentation on how the gui elements work with the module elements.
I am programming max externals, vst/au plugins via Juce, pure data externals, etc. right now. Everybody got their own system.
If you can point me to the appropriate documentation or even code that somebody else has written, that would be great. Otherwise, I might just resort to download all of the VCV related code available, and grep through all of them
Sorry, what I meant is how the ModuleWidget objects interact with the Module objects.
I quickly gathered that inputs, outputs, lights are members of the Module class. But there is no predefined access to ModuleWidget.
So, I assume ModuleWidget is “pushing” events to its Module object. That makes sense, since GUI thread is often running at a much slower rate than the audio thread. But usually events have a way to register callbacks, etc. I didn’t find an obvious place to do that or hook into the events. Then there is the dataToJson functions, which I assume is how parameters are being sent or retrieved? They seemed to be similar the Audio parameter trees from Juce? Then the question comes, do I check them on a regular basis or do I get an event callback? And this event callback, is it via inheritance and overload or via registering? All of this wasn’t obvious.
I am ok with digging through code. It’s just bit tedious to build up an idea of how the different parts of VCV interact with each other. Like you said, there are 100 ways to do things, I just want to figure out the most efficient way to do things quickly within the scope of VCV Rack.
The only thing data To/From is for is retrieving after a close. This is not saved in the module code rather it is saved in the patch, when the patch file .vcv is loaded it retrieves this data and updates the parameters for each instance of a module. For example if you have an array in the module code the only way to change the array values for that instance of the module is by retrieving them from the json the values get inserted to the array indexes and your code would update that instance of that module. If you add a new instance of the module to the Rack the array values would be initialised as they are in the module.cpp. When you close Rack the data for each instance is pushed to the .vcv file for retrieval upon opening Rack again. It is only called on open and pushed on close.
I know this is a late reply, but may help the OP or anyone else who finds this topic. The minimum code to access a Text field from the module is shown below. This will need some work, as in it’s current format will not display correctly in the browser, and accessing the text at the audio sample rate is probably undesired.
You should not do it this way, the widget should pull the text from the module, you are pushing the text into the widget.
First is it a waste of resources because the GUI has a much lower refresh rate than audio processing, second it won’t work in Rack v2 in headless mode when a module runs without a ModuleWidget.
Thanks for the quick response, My intention was the bare minimum code to show accessing a widget from a module, I am aware you would not do this at the audio sample rate, as I mentioned in my post.
I was not aware this would not work in V2, I would assume a null pointer check on the TextField in the module would be the correct way, I am always open to learning an improved method.
I am not intending to use this in a production module, but I am using this method in a debugging tool for my own use.
As @stoermelder says, the code you posted has some major problems. If somebody searches this forum for “textField” and finds this code, they could easily be lead in a direction that will cause them problems. This is how I would modify the code:
PitchLog (your Module) should not have a TextField member at all
PitchLog should have std::string variable (call it textValue) that stores the value that will be displayed in the text field
PitchLogWidget (ModuleWidget) should have the TextField member:
override ModuleWidget::step() in PitchLogWidget to check for the existence of “module”, and set the value of its text field : textField->setText(module->textValue)