Rack v1 development blog

I don’t know the complete context of what this is about, but on the surface it looks like you are trying to handle possible formulas used by a parameter. You could consider letting the module implement the formula. And allow for custom text.

To be more concrete about it, here are some potential features.

  1. Number precision. Something like a printf string would be the most flexible.
  2. For the formula, in VST anything is allowed. Functions could be allowed. This could be function pointers for to and from display land. (Other hosts have a 0 to 1 internal representation, e.g. VST). I believe that only AU has restricted formulas.
  3. Custom text is frequently used for stepped values. Some platforms have the concept of stepped values and allow strings for the values. (e.g. AUParameter valueStrings)

You can define your own ParamQuantity subclass and use it with the config() function, but that is beyond the scope of my “tutorial”. See the headers for full details.

2 Likes

Cool. Just wanted to makes sure that these features were covered or at least considered. Thanks!

That’s a lot of great features Andrew! Really looking forward to this. I think you forgot something you mentioned: Added facility for vendor supplied presets

Thanks Andrew. At the risk of getting slapped around and sounding ungrateful…

Does the Fundamental plugin not need a stereo mixer? It seems pretty basic now, especially given that we have all these wonderful stereo modules, just in Audible Instruments alone. IMHO Fundamental:Mixer can best be characterized as a “mono submixer”, which is fine for that purpose. There are no stereo mixers in the Audible Instruments or Befaco plugins either. I’m guessing that Fundamental:Mixer could get a pretty simple overhaul to make it stereo. Doesn’t even need panning.

Of course my comment only makes sense if: A) Stereo can be considered “basic”, and B) The idea is that, with the combination of Core, Fundamental (and maybe throw in Befaco and Audible) you can do “all the basics” (for whatever definition of that).

(and I promise I wont mention a basic quantizer)

Pedantically a stereo mixer is a mono-mixer, just with one fader optionally locked to the other one. Even panning knobs are “just” a convenience for this.

I know everything is x times mono, but you know what I mean. I’m imagining stereo outputs and the inputs being stereo pairs with right normalized to left. That’s it.

  1. This is off-topic in this thread.
  2. You could ask that about pretty much every module function that exists.
  3. You would be surprised how rigid Fundamental modules are. If one small change is made, it can break people’s patches.

That’s fair enough Andrew

Is there a plugin example of how to create context menu entries with v1?

1 Like

Core MIDI-CV has a lot of menu items.

1 Like

Doh. Didn’t even think to look in Core. Thanks!

I’m beginning to add polyphony to Fundamental modules. I wanted to try the new simd library on a polyphony application, and it works better than expected. Fundamental VCA-2 has a 3x speedup when processing 16 polyphonic channels with SSE vs serially. The code is nearly as readable as a serial version (https://github.com/VCVRack/Fundamental/blob/v1/src/VCA.cpp#L37-L91) with the main differences being

  • You have to f32_4::load() and v.store() to convert from a float* to f32_4 vector and vise-versa.
  • You can’t branch with if. You can instead use masking, e.g.
// Wrap on the interval [-0.5, 0.5)
phase -= (phase >= 0.5f) & 1.f;

(Although note that phase -= trunc(phase); is probably faster for wrapping on the interval [0, 1). Just demonstrating this trick.)

  • You must process blocks of 4 floats. I use for (int c = 0; c < channels; c += 4) for this. If you have only 1 channel (or any non-multiple of 4), this will process 4 instead, but at virtually no wasted cost.
  • All functions like sin() or pow() are implemented in simd/functions.hpp, so don’t prefix them with std::.

Once you get the hang of it, writing SIMD code is only slightly more involved than writing your serial reference implementation (which you should do first).

7 Likes

Awesome, beautiful code! Thanks for sharing this, open source is so cool :slight_smile:

2 Likes

Added a helper.py script to the Rack v1 repository for quickly creating new plugins and modules. Here’s an example session.

~/VCV/Rack/plugins ❯ ../helper.py createplugin MyPlugin
Plugin name [MyPlugin]: My Plugin
Version [1.0.0]:
License (if open-source, use license identifier from https://spdx.org/licenses/) [proprietary]: CC0-1.0
Author []: VCV
Author email (optional) []: contact@vcvrack.com
Author website URL (optional) []: https://vcvrack.com/
Plugin website URL (optional) []:
Manual website URL (optional) []:
Source code URL (optional) []:
Donate URL (optional) []:
Manifest created at MyPlugin/plugin.json
Created template plugin in MyPlugin/
Initialized empty Git repository in ~/VCV/Rack/plugins/MyPlugin/.git/
You may use `make`, `make clean`, `make dist`, `make install`, etc in the MyPlugin/ directory.

~/VCV/Rack/plugins ❯ cd MyPlugin

~/VCV/Rack/plugins/MyPlugin ❯ ls
Makefile  plugin.json  res  src

~/VCV/Rack/plugins/MyPlugin ❯ mv ../MyModule.svg res/

~/VCV/Rack/plugins/MyPlugin ❯ ../../helper.py createmodule MyModule
Module name [MyModule]: My Module
One-line description (optional) []:
Tags (comma-separated, see https://github.com/VCVRack/Rack/blob/v1/src/plugin.cpp#L543 for list) []: vco, polyphonic
Added MyModule to plugin.json
Components extracted from res/MyModule.svg
Source file generated at src/MyModule.cpp

~/VCV/Rack/plugins/MyPlugin ❯ make
g++  -Wsuggest-override -std=c++11  -fPIC -I../../include -I../../dep/include -MMD -MP -g -O3 -march=nocona -funsafe-math-optimizations -Wall -Wextra -Wno-unused-parameter -DARCH_LIN -c -o build/src/plugin.cpp.o src/plugin.cpp
g++  -Wsuggest-override -std=c++11  -fPIC -I../../include -I../../dep/include -MMD -MP -g -O3 -march=nocona -funsafe-math-optimizations -Wall -Wextra -Wno-unused-parameter -DARCH_LIN -c -o build/src/MyModule.cpp.o src/MyModule.cpp
g++ -o plugin.so build/src/plugin.cpp.o build/src/MyModule.cpp.o  -shared

~/VCV/Rack/plugins/MyPlugin ❯ ls
build  Makefile  plugin.json  plugin.so  res  src

Instructions for creating panels are shown by running helper.py createmodule. Here’s a copy.

Instructions for creating a panel:

Note: This information is probably out of date. See https://vcvrack.com/manual/Panel.html

  • Only Inkscape is supported by this script and Rack’s SVG renderer.
  • Create a document with units in “mm”, height of 128.5 mm, and width of a multiple of 5.08 mm (1 HP in Eurorack).
  • Design the panel.
  • Create a layer named “widgets”.
  • For each component, create a shape on the widgets layer.
    • Use a circle to place a component by its center.
      The size of the circle does not matter, only the center point.
      A create*Centered() call is generated in C++.
    • Use a rectangle to to place a component by its top-left point.
      This should only be used when the shape’s size is equal to the component’s size in C++.
      A create*() call is generated in C++.
  • Set the color of each shape depending on the component’s type.
    • Param: red #ff0000
    • Input: green #00ff00
    • Output: blue #0000ff
    • Light: magenta #ff00ff
    • Custom widgets: yellow #ffff00
  • Hide the widgets layer and save to res/<module slug>.svg.
7 Likes

A few of the specifics in this surprise me. I expect that

for (int c = 0; c < channels; c += 4) { v[c / 4] = ...

would produce worse code than

for (unsigned c = 0; c < channels; c += 4) { v[c >> 2] = ...

but I’d have to disassemble to be sure. Also, line 72 uses std::pow() while line 81 uses pow() ?

I’d be surprised if those don’t generate the same code. The vector pow has the signature f32_4 pow(f32_4, f32_4) and is in the simd namespace. If you want to use them both without namespaces, add using std::pow; in your function. This is useful when writing generic functions and classes.

I believe they can if -ffast-math is used. I think there is one more aggressive than fast math, it’s name escapes me right now.

I did some (unrelated to Rack) tests and when no optimization flags are in place, GCC would just call out to the standard library. Even if told that it was OK to generate AVX code it would still do so. Although once fast math is turned on, it will use the native math opcodes instead of the C functions (and then once it was willing to do that it was further willing to vectorize them.)

-ffast-math has no effect on integers, at least in your two “for” loops example.

A post was split to a new topic: UI text is blurry