diff --git a/Migrate1.md b/Migrate1.md index d491f7c..0c1e053 100644 --- a/Migrate1.md +++ b/Migrate1.md @@ -1,14 +1,18 @@ # Migrating 0.6 plugins to Rack v1 -**This document is a draft. It is not recommended to migrate plugins at this time. If you begin now, you will likely need to follow this guide again when the Rack v1 API is stabilized.** +**This document is a draft. It is not recommended to migrate plugins at this time. If you begin now, you will likely need to follow this guide again when the Rack v1 API is stable.** ## The easy way: using the `rack0.hpp` compatibility header Change `#include "rack.hpp"` to `#include "rack0.hpp"` -Create a `plugin.json` manifest file for your plugin and all modules based on the [Template manifest](https://github.com/VCVRack/Template/blob/v1/plugin.json) (TODO add actual manifest template/guide). +Create a `plugin.json` manifest file for your plugin using the `helper.py` script included in the Rack SDK. +When prompted, don't overwrite the module .cpp file. +```bash +python /helper.py createmodule +``` -Remove `SLUG` and `VERSION` from the `Makefile` and ` p->slug = ...` and `p->version = ...` from your plugin's main `.cpp` file, since they are now defined in `plugin.json`. +Remove `SLUG` and `VERSION` from the `Makefile`, and remove ` p->slug = ...` and `p->version = ...` from your plugin's main `.cpp` file, since they are now defined in `plugin.json`. For each module, change the `Model::create` call ```cpp @@ -18,63 +22,101 @@ to ```cpp Model *modelMyModule = Model::create("MyModule"); ``` +since the plugin name, module name, and module tags are now defined in `plugin.json`. + +For the following replacements, make sure you have perl installed (`perl -v`), and paste these lines into your terminal in the root of your plugin directory to automatically make replacements. +It might even be a good idea to review the changes and `git commit` between each step. -Make the following string replacements (requires Perl). +Rename the `plugin` variable to avoid a name collision with the `plugin::` namespace. +```bash +perl -pi -e 's/\bplugin\b/pluginInstance/g' src/* ``` -# Rename `plugin` variable to avoid a name collision with the `plugin::` namespace -perl -pi -e "s/\bplugin\b/pluginInstance/g" src/* - -# Change `X::create()` functions to `createX()` -perl -pi -e "s/Model::create/createModel/g" src/* -perl -pi -e "s/ParamWidget::create/createParam/g" src/* -perl -pi -e "s/ModuleLightWidget::create/createLight/g" src/* -perl -pi -e "s/Port::create/createPort/g" src/* -perl -pi -e "s/Port::OUTPUT/PortWidget::OUTPUT/g" src/* -perl -pi -e "s/Port::INPUT/PortWidget::INPUT/g" src/* -perl -pi -e "s/Widget::create/createWidget/g" src/* -perl -pi -e "s/MenuLabel::create/createMenuLabel/g" src/* -perl -pi -e "s/MenuItem::create/createMenuItem/g" src/* - -# Change `to/fromJson()` to `dataTo/FromJson()` -perl -pi -e "s/toJson/dataToJson/g" src/* -perl -pi -e "s/fromJson/dataFromJson/g" src/* +Rename `X::create()` functions to `createX()`. +```bash +perl -pi -e 's/Model::create/createModel/g' src/* +perl -pi -e 's/ParamWidget::create/createParam/g' src/* +perl -pi -e 's/ModuleLightWidget::create/createLight/g' src/* +perl -pi -e 's/Port::create/createPort/g' src/* +perl -pi -e 's/Port::OUTPUT/PortWidget::OUTPUT/g' src/* +perl -pi -e 's/Port::INPUT/PortWidget::INPUT/g' src/* +perl -pi -e 's/Widget::create/createWidget/g' src/* +perl -pi -e 's/MenuLabel::create/createMenuLabel/g' src/* +perl -pi -e 's/MenuItem::create/createMenuItem/g' src/* +``` +Rename `to/fromJson()` methods to `dataTo/FromJson()`. +```bash +perl -pi -e 's/toJson/dataToJson/g' src/* +perl -pi -e 's/fromJson/dataFromJson/g' src/* ``` -If your plugin uses any of Rack's `dsp/*.hpp` headers, remove the `#include` statements since they are now automatically included. +If your plugin uses any of Rack's `dsp/*.hpp` headers, remove the `#include "dsp/..."` lines since they are now automatically included by `rack.hpp`. -For most plugins, this should do it. -Compiling should generate hundreds of deprecation warnings, but it might succeed. -If not, read the compile error, and don't hesitate to ask questions in the VCV community forum or GitHub issue tracker. +Now compile your plugin. +Hundreds of deprecation warnings should appear, but it might succeed. +If so, your plugin can now be distributed as a Rack v1 plugin. +If not, read the compile errors, and don't hesitate to ask questions in the [Development category of the VCV Community](https://community.vcvrack.com/c/development) or [Rack GitHub issue tracker](https://github.com/VCVRack/Rack/issues). +If your plugin is open-source, you may even ask the [VCV Repair Team](https://github.com/VCVRack/library/issues/269) to create a pull request in your repository. ## The right way: using the Rack v1 API First complete the above section using the compatibility header as a first step. -Once it is able to compile, change `#include "rack0.hpp"` back to `#include "rack.hpp"` +Once it is able to compile, change `#include "rack0.hpp"` back to `#include "rack.hpp"`. +Add new arguments to the `step()` (now called `process()`) and `draw()` methods. +```bash +perl -pi -e 's/void (\w+::)?step\(\)/void $1process(const ProcessArgs &args)/g' src/* +perl -pi -e 's/void draw\(NVGcontext \*vg\)/void draw(const DrawArgs &args)/g' src/* +perl -pi -e 's/\bvg\b/args.vg/g' src/* +perl -pi -e 's/engineGetSampleRate\(\)/args.sampleRate/g' src/* +perl -pi -e 's/engineGetSampleTime\(\)/args.sampleTime/g' src/* +``` +Use the `APP` macro for accessing global state. +```bash +perl -pi -e 's/Font::load/APP->window->loadFont/g' src/* +perl -pi -e 's/Image::load/APP->window->loadImage/g' src/* +perl -pi -e 's/SVG::load/APP->window->loadSvg/g' src/* +``` +Use `createInput/Output()` functions instead of `createPort()`. +```bash +perl -pi -e 's/, PortWidget::INPUT//g' src/* +perl -pi -e 's/addInput\(createPort/addInput(createInput/g' src/* +perl -pi -e 's/, PortWidget::OUTPUT//g' src/* +perl -pi -e 's/addOutput\(createPort/addOutput(createOutput/g' src/* +``` +Add namespaces to global functions. +```bash +perl -pi -e 's/\bassetPlugin\b/asset::plugin/g' src/* +perl -pi -e 's/\brandomUniform\b/random::uniform/g' src/* +perl -pi -e 's/\brandomNormal\b/random::normal/g' src/* +perl -pi -e 's/\brandomu32\b/random::u32/g' src/* +``` +Change `.value` to getters and setters, and change `.active` to `isConnected()`. +```bash +perl -pi -e 's/(params\[.*?\])\.value/$1.getValue()/g' src/* +perl -pi -e 's/(inputs\[.*?\])\.value/$1.getVoltage()/g' src/* +perl -pi -e 's/(outputs\[.*?\])\.value = (.*?);/$1.setVoltage($2);/g' src/* +perl -pi -e 's/(inputs\[.*?\])\.active/$1.isConnected()/g' src/* +perl -pi -e 's/(outputs\[.*?\])\.active/$1.isConnected()/g' src/* ``` -# Use `APP` macro for accessing global state -perl -pi -e "s/engineGetSampleRate/APP->engine->getSampleRate/g" src/* -perl -pi -e "s/engineGetSampleTime/APP->engine->getSampleTime/g" src/* -perl -pi -e "s/Font::load/APP->window->loadFont/g" src/* -perl -pi -e "s/Image::load/APP->window->loadImage/g" src/* -perl -pi -e "s/SVG::load/APP->window->loadSvg/g" src/* - -# Use `createInput/Output()` functions instead of `createPort()` -perl -pi -e "s/, PortWidget::INPUT//g" src/* -perl -pi -e "s/addInput\(createPort/addInput(createInput/g" src/* -perl -pi -e "s/, PortWidget::OUTPUT//g" src/* -perl -pi -e "s/addOutput\(createPort/addOutput(createOutput/g" src/* - -# Add namespaces to global functions -perl -pi -e "s/randomUniform/random::uniform/g" src/* -perl -pi -e "s/randomNormal/random::normal/g" src/* - -# Change `void draw(NVGcontext *vg)` to `void draw(const DrawContext &ctx)` -perl -pi -e "s/draw\(NVGcontext \*vg\)/draw\(const DrawContext &ctx\)/g" src/* -perl -pi -e "s/\(vg/(ctx.vg/g" src/* -perl -pi -e "s/draw\(vg\)/draw\(ctx\)/g" src/* - -# Add the `dsp::` namespace to dsp classes -# TODO +Add the `dsp::` namespace to dsp classes. +TODO +```bash +``` +Add `config()` to the `Module` constructor, and add `setModule` to the `ModuleWidget` constructor. +```bash +perl -pi -e 's/: Module\(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS\) \{/{\n\t\tconfig(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);/g' src/* +perl -pi -e 's/: ModuleWidget\(module\) \{/{\n\t\tsetModule(module);/g' src/* +``` + +Now make sure your plugin compiles. + +### Adding new Rack v1 features + +You are now ready to add optional Rack v1 features to your plugin. + +Parameters now have optional labels. +Add `Param::config()` to the `Module` constructor. +```cpp +params[X_PARAM].config(0.0, 1.0, 0.0, "Label"); ``` diff --git a/VoltageStandards.md b/VoltageStandards.md index 4871e84..9c2f6fa 100644 --- a/VoltageStandards.md +++ b/VoltageStandards.md @@ -5,9 +5,10 @@ You can measure absolute voltage levels using modules like Fundamental Scope. Rack attempts to model Eurorack standards as accurately as possible, but this is a problem for two reasons: there are very few actual "standards" in Eurorack (The only rule is that you can always find a module which breaks the rule), and there are a few differences between digital (finite sample rate) and analog (infinite sample rate). -## Audio and Modulation +## Levels -Audio outputs are typically **±5V** (before bandlimiting is applied), and CV modulation sources are typically **0 to 10V** (unipolar CV) or **±5V** (bipolar CV). +Signals should typically be \\(10V_{pp}\\) (peak-to-peak). +This means that audio outputs should typically be **±5V** (before bandlimiting is applied), and CV modulation sources should typically be **0 to 10V** (unipolar CV) or **±5V** (bipolar CV). ## Output Saturation