Migrating v0.6 Plugins to v1¶
This is a step-by-step guide for migrating plugins using the Rack v0.6 API to Rack v1. There are three phases of porting.
- Phase 1: Quickly produces a valid Rack v1 plugin.
- Phase 2: Modernizes the code by replacing deprecated v0.6 function calls with new v1 functions.
- Phase 3: Takes advantage of new Rack v1 features such as parameter labels and polyphony.
Prerequisites¶
Install new build dependencies.
- jq for parsing JSON when building plugins
- Python 3.6+ for running Rack’s script
- Perl for replacing text with regex.
Mac¶
brew install jq python
Windows¶
pacman -S mingw-w64-x86_64-jq python3
Phase 1: Using the compatibility header¶
1.1¶
to your plugin’s root directory. Create a manifest file for your plugin using the helper script included in the Rack SDK.
python3 <Rack SDK>/helper.py createmanifest <plugin slug>
1.2¶
For each module in your plugin, add an entry to using the helper script.
python3 <Rack SDK>/helper.py createmodule <module slug>
1.3¶
Remove and from the , and remove and from your plugin’s main file, since they are now defined in .
1.4¶
Change to to access deprecated functions.
1.5¶
For each module, remove the author, module name, and tags from the call, since they are now defined in . For example, change
Model *modelMyModule = Model::create<MyModule, MyModuleWidget>("Template", "MyModule", "My Module", OSCILLATOR_TAG);
to
Model *modelMyModule = Model::create<MyModule, MyModuleWidget>("MyModule");
1.6¶
Make the following regex replacements by pasting these lines into your terminal in the root of your plugin directory. It is a good idea to review the changes and between each step, in case an automatic replacement goes wrong.
1.6.1¶
Rename the variable to avoid a name collision with the namespace.
perl -i -pe 's/\bplugin\b/pluginInstance/g' src/*
1.6.2¶
Rename functions to .
perl -i -pe 's/Model::create/createModel/g' src/*
perl -i -pe 's/ParamWidget::create/createParam/g' src/*
perl -i -pe 's/ModuleLightWidget::create/createLight/g' src/*
perl -i -pe 's/Port::create/createPort/g' src/*
perl -i -pe 's/Port::OUTPUT/PortWidget::OUTPUT/g' src/*
perl -i -pe 's/Port::INPUT/PortWidget::INPUT/g' src/*
perl -i -pe 's/Widget::create/createWidget/g' src/*
perl -i -pe 's/MenuEntry::create\(\)/new MenuEntry/g' src/*
perl -i -pe 's/MenuLabel::create/createMenuLabel/g' src/*
perl -i -pe 's/MenuItem::create/createMenuItem/g' src/*
1.6.3¶
Rename methods to .
perl -i -pe 's/toJson/dataToJson/g' src/*
perl -i -pe 's/fromJson/dataFromJson/g' src/*
1.6.4¶
Add to the constructor, and add to the constructor.
perl -i -pe 's/: Module\(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS\) \{/{\n\t\tconfig(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);/g' src/*
perl -i -pe 's/: Module\(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS\) \{/{\n\t\tconfig(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);/g' src/*
perl -i -pe 's/: ModuleWidget\(module\) \{/{\n\t\tsetModule(module);/g' src/*
1.7¶
If your plugin uses any of Rack’s headers, remove the lines since they are now automatically included by .
1.8¶
The event API has been overhauled in v1. If you use event handler methods in your custom widgets, see event.hpp and widget/Widget.hpp for new methods and event classes.
Once completed, your plugin may compile, although many deprecation warnings may appear. If there are too many warnings to see the errors, you may temporarily add to your .
1.9¶
Your s must gracefully handle a NULL argument, otherwise Rack will crash when the Module Browser attempts to display your module. etc. gracefully handle NULL, but if you’ve written custom widgets with a pointer, make sure you check before accessing the pointer.
1.10¶
Test your plugin in Rack by adding your modules, moving parameters, clicking custom widgets, and searching your plugin in the Module Browser.
If your plugin still does not build, read the compile errors, and don’t hesitate to ask questions in the Development board of the VCV Community or Rack’s GitHub issue tracker about the v1 API. If your plugin is open-source, you may even ask the VCV Repair Team to create a pull request for you.
Phase 2: Updating your code to the Rack v1 API¶
2.1¶
Once your plugin can be compiled, change back to .
2.2¶
Add new arguments to the (now called ) and methods.
perl -i -pe 's/void (\w+::)?step\(\)/void $1process(const ProcessArgs& args)/g' src/*
perl -i -pe 's/void draw\(NVGcontext \*vg\)/void draw(const DrawArgs& args)/g' src/*
perl -i -pe 's/\bvg\b/args.vg/g' src/*
Note: has not been renamed, but this replacement will incorrectly rename it.
2.3¶
Use the argument struct to access the sample rate/time.
perl -i -pe 's/engineGetSampleRate\(\)/args.sampleRate/g' src/*
perl -i -pe 's/engineGetSampleTime\(\)/args.sampleTime/g' src/*
Note: This only works inside methods. You can call and anywhere in your code, although this is slightly slower than the above.
2.4¶
Use the macro for accessing global state instead of calling global functions.
perl -i -pe 's/Font::load/APP->window->loadFont/g' src/*
perl -i -pe 's/Image::load/APP->window->loadImage/g' src/*
perl -i -pe 's/SVG::load/APP->window->loadSvg/g' src/*
2.5¶
Use functions instead of .
perl -i -pe 's/, PortWidget::INPUT//g' src/*
perl -i -pe 's/addInput\(createPort/addInput(createInput/g' src/*
perl -i -pe 's/, PortWidget::OUTPUT//g' src/*
perl -i -pe 's/addOutput\(createPort/addOutput(createOutput/g' src/*
2.6¶
Add namespaces to global functions.
perl -i -pe 's/\bassetGlobal\b/asset::system/g' src/*
perl -i -pe 's/\bassetLocal\b/asset::user/g' src/*
perl -i -pe 's/\bassetPlugin\b/asset::plugin/g' src/*
perl -i -pe 's/\brandomUniform\b/random::uniform/g' src/*
perl -i -pe 's/\brandomNormal\b/random::normal/g' src/*
perl -i -pe 's/\brandomu32\b/random::u32/g' src/*
perl -i -pe 's/\bstringf\b/string::f/g' src/*
2.7¶
Change to getters and setters, and change to .
perl -i -pe 's/(params\[.*?\])\.value/$1.getValue()/g' src/*
perl -i -pe 's/(inputs\[.*?\])\.value/$1.getVoltage()/g' src/*
perl -i -pe 's/(outputs\[.*?\])\.value = (.*?);/$1.setVoltage($2);/g' src/*
perl -i -pe 's/(inputs\[.*?\])\.active/$1.isConnected()/g' src/*
perl -i -pe 's/(outputs\[.*?\])\.active/$1.isConnected()/g' src/*
2.8¶
Add the namespace to dsp classes.
perl -i -pe 's/\b(quadraticBipolar|cubic|quarticBipolar|quintic|sqrtBipolar|exponentialBipolar|BooleanTrigger|SchmittTrigger|PulseGenerator|RealFFT|ComplexFFT|RCFilter|PeakFilter|SlewLimiter|ExponentialSlewLimiter|ExponentialFilter|RealTimeConvolver|MinBlepGenerator|stepEuler|stepRK2|stepRK4|SampleRateConverter|Decimator|Upsampler|RingBuffer|DoubleRingBuffer|AppleRingBuffer|VuMeter|hann|hannWindow|blackman|blackmanWindow|blackmanNuttall|blackmanNuttallWindow|blackmanHarris|blackmanHarrisWindow|Frame|VUMeter)\b/dsp::$1/g' src/*
2.9¶
Moved to Phase 1.6.4.
2.10¶
For each param in each module, copy from to a new call in your constructor. Then remove the values from .
For example, if you have the line
addParam(createParam<BlackKnob>(Vec(10, 20), module, MyModule::LEVEL_PARAM, 0.f, 10.f, 5.f));
create a new line
configParam(LEVEL_PARAM, 0.f, 10.f, 5.f);
in the constructor, and change the original line to
addParam(createParam<BlackKnob>(Vec(10, 20), module, MyModule::LEVEL_PARAM));
You can automate this process by running
perl -nle 'print "configParam($1, \"\");" while /createParam.*?module, (.*?)\)/g' src/*
and copying the respective groups of lines into each module’s constructor. Then remove the arguments with
perl -i -pe 's/(createParam.*?module, .*?)(,.*?)\)/$1)/g' src/*
Now make sure your plugin compiles.
Phase 3: Adding new Rack v1 features¶
You are now ready to add optional Rack v1 features to your plugin.
You may add parameters labels, units, and nonlinear scaling to be displayed when users right-click on a parameter or enable View > Parameter tooltips. See Module::configParam().
If you with to add support for polyphonic cables, see How polyphonic cables will work in Rack v1, Making your monophonic module polyphonic, and engine/Port.hpp.