I’m curious what the best workflow for developing native plugins might be? I have an idea for a spectral type plugin but keen to develop as close to the hardware as possible without the extra VCV pieces. Currently workflow is:
compile module to .mmplugin
put on usb stick and move across to MM
test
iterate
The remove usb stick part is too impractical really though. Can the module be copied / reloaded by JTAG etc (ideally without reflashing while firmware)? Or is it possible to test mmplugins in the simulator? Or in a similar thread there was discussion of loading patches over serial connection, maybe possible here too? Would the Wifi expander allow easier workflow for the development cycle?
I can always go back to VCV first then port (as it’s easier to debug) but curious if there’s a better way?
Good question!
I did a lot of testing in the simulator for plugins.
The thing I did was create a branch in the firmware repo, and then add the “plugin” as a built-in. Then you can run the simulator and play with it freely.
You can see an example of that with the rack-fundamental-builtin branch and/or the airwindows-builtin branch. The Wifi Module lets you transfer plugin files, too, though I haven’t tried that workflow for development.
Doing it as a built-in also lets you test on MM hardware via JTAG, though with JTAG speeds, it’s not much faster than unloading a plugin, swapping a USB Drive, and re-loading it.
The basic procedure for making a plugin into a built it is:
add BRAND to firmware/vcv_ports/brands.cmake
put a CMakeLists.txt file and the source files needed to build the plugin in firmware/vcv_ports/BRAND/
add a new section for the brand in firmware/vcv_ports/internal_plugin_manager.hh, just copy/paste from another brand and update the module and brand names.
add PNG assets to firmware/assets/BRAND/. Remember if running on hardware you will need to do an update for the assets image (use the build/metamodule-firmware-vx.x.x-assets.zip file to update). If running on simulator you can just do make asset-image from the firmware dir to regenerate the image that the simulator uses.
Another approach, which is what we did for the 4ms modules is to create a wrapper in VCV for the module code. Your native plugin is a class derived from CoreProcessor, and then you have a VCV rack plugin project that generates a VCV module when given the CoreProcessor and an array of MetaModule::Elements.
This is how we did it for the 4ms modules:
The Element list is in a constexpr struct called the info structs, you can see them here:
So then to create the model, it’s like this: rack::Model* modelMyModel = GenericModule<MyModelInfo>::create()
The slug in MyModelInfo is used to query the registry (ModuleFactory) and get a pointer to the CoreProcessor type. But a more simple way would be to modify GenericModule a little bit and do something like:
I can happily build, and debug using vscode built-in plugins using the metamodule repo and the simulator subdirectory. My question is can I debug using simulator and compiled .mmplugin objects somehow?
Context is experimenting with compiling Befaco Oneiroi which will have to remain closed source, and which I’ll have to distribute as a .mmplugin eventually, so it gets a bit awkward debugging as built-in, copying out, building in SDK etc. There are a few other changes between “built in” and metamodule-example-plugins right? Maybe the actual modified vcv source stays the same, and we just have different bits of surrounding structure (vcv_ports/glue in one, and plugin-sdk specific cmakefiles in the other)? Hope this makes sense!
Yeah, that’s basically it. The simulator can’t load an .mmplugin file, but you can build the plugin as a built-in without too much trouble. I did this when developing a few brands (Bogaudio, Fundamental, Airwindows…)
Since Befaco is already a built-in brand, maybe you could just add Oneiroi as a module within the Befaco brand, and then run it in the simulator. Once it’s all working well, you could move the code to the plugin.
But-- I’ve been meaning to document the process of running a plugin as a built-in in the simulator. I’d like to make it more automatic – right now you have to a few manual steps:
Append the brand name (let’s call it NewBrand) to vcv_ports/brands.cmake
Add the VCV repo as a submodule to vcv_ports/NewBrand
Put the plugin’s CMakeLists.txt file (plus any support files if there are any) into a new dir: vcv_ports/glue/NewBrand
In the this file, put a if(BUILD_DYN_PLUGIN)...endif() around the include(....../plugin.cmake) and also the create_plugin() call. This is done in all the other vcv_ports/glue/**/CMakeLists.txt files already, so you can copy that.
You probably will need to adjust some of the paths in the CMakeLists file so it points to the vcv_ports/NewBrand sources.
Add something like this to vcv_ports/internal_plugin_manager.hh in load_internal_plugins():
I think that’s all that’s needed to run it in the simulator. There’s a cmake option you can set to build the plugin from within the firmware build, too (that’s what the cmake BUILD_DYN_PLUGIN stuff is for). Once it’s running in the simulator and all the bugs are worked out, you will need to remove the if(BUILD_DYN_PLUGIN)...endif() lines in the CMakeLists before building it outside of the firmware repo.