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.
Number precision. Something like a printf string would be the most flexible.
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.
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.
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).
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.
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).
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.
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.)