Rack development blog

Added the "brand" property to plugin.json manifests. The brand is used as a prefix to module names, e.g. Fundamental VCF, VCV Parametra, Vult Flux, Befaco Rampage.

Most plugins don’t need this. If the brand is not given or blank, the plugin name is used as the brand name. If you’ve made multiple plugins, you should set the brand of all your plugins to the same string, e.g. Vult. (In Vult’s case, it’s a good idea to add the word “free” to the module names to distinguish between their commercial version.)

This breaks the plugin ABI, but no API change is needed unless you want to add a brand name to your plugin. Another dev build will be available in about a week.

Why is this needed?

Here’s a table of a few plugins and their properties. (In the case of third-party plugins, I’m writing what I think the properties should be.)

Plugin slug Plugin name Brand Author
Fundamental Fundamental VCV VCV
VCV-Parametra Parametra VCV VCV
Befaco Befaco Befaco VCV
VultModulesFree Vult Modules Free Vult Leonardo Laguna Ruiz
Hora-AnalogDrums Hora Analog Drums Hora Hora

Note the diversity of values in the Brand column. In some cases, it’s the author name. In some cases, it’s the plugin name. In others, it’s not exactly equal to either.

But in all cases, the brand should be the most natural prefix when saying the module’s full name.

2 Likes

As some of you know, in order to produce a Linux plugin build that works on all Linux distros supported by Rack, you must compile against glibc 2.23 and libstdc++ 5.4.0, which is what Ubuntu 16.04 uses. This is because the ABIs of the GNU implementations of the C and C++ standard library change every few years.

Previously the only way to correctly do this is to use Ubuntu 16.04 (and thus an old version of GCC) for building plugins, either in a virtual machine, Docker container, or installed on a system.

Thanks to wheybags’ glibc_version_header, you can add the following to your plugin’s Makefile and build on any Linux distro, even bleeding edge Arch with GCC 9 if you want.

FLAGS += -include force_link_glibc_2.23.h

This works by specifying each glibc symbol version explicitly instead of defaulting to the newest versions (which might be beyond 2.23). This header is not included by default because it only works in probably ~75% of cases. Your plugin will still fail to load in Ubuntu 16.04 if you

  • use certain libstdc++ code. Most of the C++ stdlib is header-only but not all of it. glibc_version_header only fixes glibc symbols, not libstdc++ symbols. Furthermore, libstdc++ links to glibc and will use newer symbols unless you compile libstdc++ yourself and statically link it (which is more complicated than it’s worth).
  • build dependencies without passing it that flag.
  • use dlopen, since libdl occassionally changes its ABI but doesn’t offer versioned symbols (at least in my distro’s libdl build).

So if you use glibc_version_header, be sure to give your binary to an Ubuntu 16.04 user to test that it loads. Or test by running

objdump -p plugin.so

and looking at the Version References: section for higher versions of GLIBC and GLIBCXX.

This post is only relevant if you are building your own Linux plugin binaries. None of the above is needed for

  • Windows, since Mingw-w64 uses Microsoft’s MSVCRT.DLL for its C stdlib and Rack bundles libstdc++6.dll
  • Mac, since Rack and plugins are built with Apple LLVM’s -mmacosx-version-min=10.7, which is a fantastic feature that tells clang to link to the libc ABI used by Mac 10.7.
  • Source code git repos submitted to https://github.com/VCVRack/library or private ZIP files emailed to VCV, since VCV’s build service uses an Ubuntu 16.04 Docker container for Linux builds.

(The length and complexity of this post is one of the reasons why Linux is often not targeted by commercial software vendors, such as VST developers.)

4 Likes

I’m considering removing favorite modules and sorting by most recently used. Discuss at https://github.com/VCVRack/Rack/issues/1292

7 Likes

Ports now encode their connectedness state in their number of channels. Inputs and outputs are now connected iff (if and only if) channels > 0 and disconnected iff channels == 0.

The behavior of Port::setChannels has changed slightly:

  • If you call setChannels(0), it will actually set the number of channels to 1 but will clear all voltages to 0V. In English this means “a cable is still technically connected but is carrying zero voltage as if it’s disconnected.”
  • If you call setChannels(channels) when the port is disconnected, your request is ignored, and the number of channels will remain at 0. In English, “I try to push N channels out of the port, but since no cable is connected, there are still technically 0 channels coming out of the port.”

Monophonic modules don’t need to change anything. Most polyphonic modules don’t need to change anything. However, consider the following code.

int channels = inputs[AUDIO_INPUT].getChannels();
for (int c = 0; c < channels; c++) {
	...
	outputs[AUDIO_OUTPUT].setVoltage(v, c);
}
outputs[AUDIO_OUTPUT].setChannels(channels);

If AUDIO_INPUT is disconnected, channels is 0, the for-loop is skipped, and AUDIO_OUTPUT will have 1 channel, which is set to 0V. This is very elegant behavior for such simple code for an FX processor module. But users want their filters to self-resonate when no cable is patched. In this case I would suggest limiting the minimum number of output channels to 1, e.g.

int channels = std::max(1, inputs[AUDIO_INPUT].getChannels());

Summary: If you have a polyphonic module that should produce nonzero CV/audio when your “primary” input (which defines the number of channels) is disconnected, add std::max(1, ...) to your code.

5 Likes

All monophonic modules should now sum the channel voltages of its audio inputs (but not CV inputs). See the last paragraph of https://vcvrack.com/manual/VoltageStandards.html#polyphony.

The reasoning is that people will plug poly cables into your mono module “by accident”, and summing is the least surprising, and perhaps even welcoming, result.

4 Likes

What is the formula for scaling parameter values for display using configParam(..., displayBase, displayMultiplier, displayOffset)?

Where v is the parameter value:

  • Linear displayBase = 0: v * displayMultiplier + displayOffset
  • Logarithmic displayBase < 0: log(v) / log(-displayBase) * displayMultiplier + displayOffset
  • Exponential displayBase > 0: pow(displayBase, v) * displayMultiplier + displayOffset

Useful examples:

  • configParam(PW_PARAM, 0, 1, 0.5f, "Pulse width", "%", 0, 100) displays as “Pulse width 50%” at the default value
  • configParam(FREQ_PARAM, -54, 54, 0, "Frequency", " Hz", dsp::FREQ_SEMITONE, dsp::FREQ_C4) displays as “Frequency 261.6 Hz”
  • Or, configParam(FREQ_PARAM, -4, 4, 0, "Frequency", " Hz", 2, dsp::FREQ_C4) since octaves are easier to work with than semitones.
  • configParam(LVL_PARAM, 0, M_SQRT2, 1, "Ch 1 level", " dB", -10, 40) displays as “Ch 1 level 0 dB” and scales with gain = pow(v, 2) in the DSP kernel.
2 Likes

All VCV GitHub repositories now default to the v1 branch. Template has been deprecated, as it has been replaced by the helper.py script.

5 Likes

The plugins Core and Fundamental now have the brand “VCV”, so their modules are now officially called “VCV Audio-8”, “VCV VCO-1”, “VCV Scope”, etc.

1 Like

Another dev build:

I should have mentioned this in the last dev build post, but because the Rack v1 ABI is not yet stable, plugin binaries are only guaranteed to work with the exact version they are compiled against. When releasing a dev build of your plugin, you must specify to users which Rack version it is compatible with.

5 Likes

Reminder: If you compile Rack from source, all plugins must be recompiled whenever you pull and recompile Rack, until the ABI is stabilized. Please do not post issues to GitHub until you have recompiled all Rack plugins against the current source tree or a matching SDK version.

EDIT: I have realized that it is also necessary to delete your <Rack user dir> directory after upgrading if you run these binaries in non-dev mode (without the -d flag). This forces the Fundamental plugin to be re-copied to the <Rack user dir>/plugins directory.

2 Likes

The VCV Plugin Manager is now called VCV Library, and the server is now live for v1. The Library client is now functional in the latest Rack source. Report any bugs with the Library client/server.

I’m opening a discussion at Smoothing user migration to Rack v1 that addresses a problem many users have brought up.

I’ve added CONTRIBUTING.md if you’re into those kinds of things.

6 Likes

Decibel measurements used on VU meters, etc. should be based on 10V = 0 dB. https://vcvrack.com/manual/VoltageStandards.html#levels

2 Likes

Added getVoltageSimd(), getPolyVoltageSimd(), getNormalVoltageSimd(), getNormalPolyVoltageSimd(), and setVoltageSimd() to Port. These make working with SIMD easier for polyphonic modules. Example:

for (int c = 0; c < channels; c += 4) {
	float_4 in = inputs[IN_INPUT].getVoltageSimd<float_4>(c);
	float_4 cv = inputs[CV_INPUT].getPolyVoltageSimd<float_4>(c);
	float_4 out = in * simd::fmax(0.f, cv) / 10.f;
	outputs[OUT_OUTPUT].setVoltageSimd(out, c);
}
5 Likes

The Rack v1 plugin ABI is now stable! To celebrate, here are dev builds of the latest source.

If you have open-source plugins, please notify the Library team after your plugin is migrated to the v1 API if you have not already done so. Builds using this SDK will be made for you.

If you have freeware or commercial plugins, make Mac/Windows/Linux builds and send them to contact@vcvrack.com after your plugin is migrated to the v1 API.

28 Likes

Created Rack 1.0 promotional page at https://vcvrack.com/Rack.html.

20 Likes

Is anyone using the following element-wise SIMD vector constructors? PM me if so.

simd::float_4(float x1, float x2, float x3, float x4)
simd::int32_4(int32_t x1, int32_t x2, int32_t x3, int32_t x4)

I’m going to reverse the element order by using _mm_setr_ps() rather than _mm_set_ps() to match the order of element access.

1 Like

I plan for v1 plugins to be API-compatible with Rack v2, except for “unusual” plugins that use the deep corners of Rack’s API. ABI compatibility will break to allow Rack for DAWs to load normal Rack plugins, among other reasons, so hopefully the migration process from v1 to v2 will only involve recompiling your plugins (and optionally fixing new deprecated warnings). If by some miracle the ABI doesn’t need to change, I will simply keep the version at v1 when releasing Rack for DAWs.

I’m also looking for other possible names for Rack for DAWs

3 Likes

I will be on vacation starting Wednesday but will still be responsive to customer support, critical bugs, and business queries. I will announce San Francisco, Santa Clara, and Stanford talk dates soon. After returning from California, I will be back to work.

Rack 1.1.0 will be released on Tuesday-Wednesday containing the following features and fixes. https://github.com/VCVRack/Rack/blob/v1/CHANGELOG.md

14 Likes

In order for plugin updates to be accepted, the VCV Library team no longer allows slug changes for either plugins and modules. A slug “change” is defined by a slug that is removed at the same time that a very similar plugin/module is added. We will attempt to spot such changes manually and automatically (through scripts), but all developers should keep an eye out for mistakes/typos when migrating or updating.

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