Rack development blog

The Plugin Development Tutorial is now fully up-to-date for Rack v1. If you have been waiting for a stable API and documentation to dive into Rack plugin development, now is an excellent time to begin.

10 Likes

Rack dev and the upcoming 1.2.0 release will include an assertion that no duplicate input/output ports can be added to a ModuleWidget. This means that if you have the two lines

addInput(createInputCentered<PJ3410Port>(mm2px(Vec(0, 0)), module, MyModule::PITCH_INPUT));
addInput(createInputCentered<PJ3410Port>(mm2px(Vec(0, 0)), module, MyModule::PITCH_INPUT));

in your ModuleWidget constructor, your plugin will cause Rack to crash when your module is rendered.
I don’t have all plugins installed, but of my arbitrary selection, the following plugins crash in Rack dev and should be fixed by making sure all ports have unique port IDs (usually defined in the Input/OutputIds enum).

  • DHE-Modules (I think Fuzzy Logic H but maybe more)
  • SurgeRack
4 Likes

Rack 1.1.2 is released. Changelog: https://github.com/VCVRack/Rack/blob/v1/CHANGELOG.md

8 Likes

You can now navigate https://vcvrack.com/downloads/ for previous VCV Rack releases.

14 Likes

Added dsp::BiquadFilter to DSP library. Supports SIMD.

6 Likes

Added dsp/approx.hpp, which only has one function for computing 2^x but will later contain several approximations of common math functions for faster DSP.

9 Likes

Rack 1.1.4 has been released.

7 Likes

Added libsamplerate to Rack, so plugins no longer need to build their own copy. (Fundamental, FrozenWasteland, maybe more)
Of course, it would be a good idea to wait a month or two after the next Rack version is released before releasing a plugin that takes advantage of the included libsamplerate.

If you build Rack from source, note that you need to make dep the next time you pull and rebuild.

9 Likes

Added “Hardware” tag for hardware module clones. https://github.com/VCVRack/Rack/blob/v1/src/tag.cpp#L35

2 Likes

Developers may now use "manualUrl" for each module in your plugin manifest. However, they will not be used until Rack v2 or the upcoming VCV Library website.

7 Likes

Rack v2 Plan Overview

Major features that will define Rack v2:

  • Add scaffolding for Rack for DAWs, so that the proprietary fork is as minimal as possible, containing only plugin API wrappers.
  • Integration with future VCV Library website at https://library.vcvrack.com/, which will allow individual modules to be added to your VCV account, and possibly individually purchased modules.

Very rough development timeline:

  • 2019 Q2 - Q4: Lots and lots of new Eurorack and VCV plugins.
  • 2019 Q3 - Q4: VCV Library website, minor Rack v2 features.
  • 2019 Q4 - 2020 Q1: Rack v2. Rack for DAWs.

Expected API changes:

  • No stable symbols are planned to be changed. The plan for the Rack v2 API is for at least 90% of plugins to be recompiled for Rack v2 with 0 lines of source changes.
  • All plugins will need to change the "version" property of their plugin.json manifest to begin with "2." instead of "1." to signify that they are built with the Rack v2 SDK. However, all open-source plugins in the VCV Library will be rebuilt by us by automatically changing the old version 1.2.3 to 2.p.1.2.3 or similar. If you wish to make further updates after v2 is released, you will then need to set a “real” version such as 2.2.3.
14 Likes

Beta builds of VCV Rack 1.1.5:

Changelog: https://github.com/VCVRack/Rack/blob/v1/CHANGELOG.md
As always, see https://vcvrack.com/manual/FAQ.html#i-found-a-bug for reporting bugs.

4 Likes

Added LEDLightSlider to componentlibrary.hpp. Example:

addParam(createLightParamCentered<LEDLightSlider<GreenLight>>(
	mm2px(Vec(40.0, 40.0), module,
	VCMixer::LVL_PARAM, VCMixer::LVL_LIGHT));

Also note my use of C++ CRTP for adding appearance traits and behavioral properties to widgets. 2019-09-26-110203_348x363_scrot

Also added segment light. Example:

// In `Module`:
enum LightIds {
	ENUMS(SEGMENT_LIGHTS, 10),
	NUM_LIGHTS
};
// In `ModuleWidget()`:
SegmentDisplay* segmentDisplay = createWidget<SegmentDisplay>(mm2px(Vec(2.424, 15.564)));
segmentDisplay->box.size = mm2px(Vec(25.984, 4.524));
segmentDisplay->setLights<WhiteLight>(module, Permutation6::SEGMENT_LIGHTS, 10);
addChild(segmentDisplay);

2019-09-26-110230_396x237_scrot

8 Likes

Proposal for port metadata struct to be added to Rack v2.

4 Likes

Proposal for a buffered process() function.

2 Likes

Someone brought up a point of confusion of how the rules of polyphonic modules are defined, so I’d like to clarify the motivation behind the polyphony standard.

If a monophonic signal is patched into a polyphonic module currently running with N engines (each representing a polyphonic channel), the monophonic signal is copied to all engines.

If you’re familiar with programming, you can think of monophonic signals as “scalars” that implicitly cast to polyphonic signals (vectors) when incompatible types interact. For example, the expression a + [b1, b2, b3] should reduce to [a + b1, a + b2, a + b3].

If you’re familiar with mathematics, a monophonic signal is a rank-0 tensor (over time) while a polyphonic signal is a rank-1 tensor (over time). An operation like summing would look like (a + \vec{b})_i := a + b_i. (Note that in this analogy, rank-1 tensors with dimension 1 cannot be represented in Rack.)

The user-benefiting motivation is to be able to use the same input port (e.g. FM input) rather than two different ports (e.g. mono FM and poly FM inputs) in order to either modulate each polyphonic engine (e.g. VCO) with a same-channel polyphonic signal or to modulate all polyphonic engines with a 1-channel monophonic signal.

The standard says

The number of active engines N should be defined by the number of channels of the “primary” input

However, it is purposefully vague in specifying what a “primary” input is. In some cases, there is no primary input at all because all inputs must be treated with equal respect. Martin Lueders and I discussed that when polyphon-izing Befaco A*B+C (where neither A, B, nor C are the “primary” input), the number of engines should be computed by max(#A, #B, #C) where #x is the number of channels of input x. This allows you to mix-and-match mono and poly cables in the A, B, and C inputs, so the result is a polyphonic signal that correctly controls the rest of your polyphonic patch.

Just some thoughts if you’re developing a module that supports polyphony.

6 Likes

A few plugin developers have asked me about the difficulty of preparing your plugin for Rack v2. Will we have another Rack v0.6 -> v1 transition that requires minutes to hours of porting? No. The goal for the Rack v2 API is for at least 90% of plugins to require zero changes to code. Developers of closed-source plugins will need to send me builds of their plugins before the Rack v2 launch. The Rack v2 SDK will be released at least two weeks before Rack v2.

Of course, to take advantage of new features such as Port labels, you’ll need to add code.

4 Likes

Proposal for adding many new Module events.

1 Like

Rack v2 is being worked on, but it’ll be a while before I get around to publishing the source code.

Coming in Rack v2: Port tooltips with voltage readings of all polyphonic channels. 2019-10-27-162411_1600x900_scrot

19 Likes

Coming in Rack v2: There is no more “engine thread”. The engine can only be stepped (i.e. advanced in time) by other threads, such as the audio driver thread managed by VCV Audio or the encoder thread in VCV Recorder. This restructuring has a number of massive benefits.

  • Support for multiple audio drivers. You can use your laptop’s headphone jack, your USB audio interface, Expert Sleepers Eurorack audio interface, etc. all at the same time. No more crashes or deadlocks. Of course, only one audio driver can “drive” the engine clock rate. Other audio drivers might drop samples if their clock rates don’t match exactly. This is selectable by enabling “Primary audio module” in the module’s context menu.

2019-10-29-153606_1600x900_scrot

  • In order for each audio buffer to be delivered to your audio device, the audio thread no longer has to lock itself (telling the OS to put it to sleep), wait on the engine thread, and unlock itself (waiting for the OS to schedule the thread again). This saves 1-10 microseconds per audio buffer on average, but more importantly, it saves 100-1000 microseconds when the CPU has an unusually high workload, which could result in audio glitches.
  • The new “Host” audio driver used in Rack for DAWs will run all module code (in Module::process()) directly in the “DAW thread”. Locking the DAW thread to wait on another thread is somewhat unacceptable.
  • Modules like VCV Recorder that can run much faster than real-time can render minutes of audio in only seconds, if they are chosen as the “Primary audio module”.
  • Stability (i.e. probability of crashing) is improved, simply because there are fewer threads dancing around complicated mutexes/shared data.
  • The “Real-time priority” menu item is removed, since the thread priority is now managed elsewhere (RtAudio, etc.)
33 Likes