Polyphony reminders for plugin developers

All plugin developers should be aware of the following points when developing polyphonic modules (or monophonic, for the first point). It is also helpful for advanced users to be aware of these rules. If you see a module that does not follow the VCV Voltage Standards, send a bug report to the developer.

Audio inputs of monophonic modules should sum the polyphonic channels.

If you choose not to support polyphony, you should still sum the channels of a polyphonic cable before processing it as audio. To do this, replace getVoltage() with getVoltageSum() for all audio input ports.

For example, if a user patches a polyphonic oscillator playing a chord into a monophonic chorus module, the channels should be combined (summed) at the chorus’ input so that the entire chord is processed by the chorus.

Input ports intended for CV or hybrid CV/audio should not sum polyphonic channels, because the sum of polyphonic CV channels is usually not what the user intends.

This point is sometimes easy to forget, even for me, so if you see any monophonic audio inputs not summing polyphonic channels, send a bug report as usual.

There may be multiple “primary” input ports on your module which define your DSP engine’s number of channels.

For example, Audible Instruments Multiples has three inputs in its bottom section that are treated equally. The number of channels should be defined as the maximum number of channels in any of those ports.

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

Remember that getChannels() returns 0 for unpatched cables, while you should always set at least 1 channel for output ports, so use std::max(..., 1) when computing the your DSP engine’s number of channels.

In the above example, we must use getPolyVoltage(int channel) on each input, since any of the signals might be monophonic.

float in = inputs[C1_INPUT].getPolyVoltage(c)
	+ inputs[C2_INPUT].getPolyVoltage(c)
	+ inputs[C3_INPUT].getPolyVoltage(c);

getPolyVoltage(c) returns channel c, or if the port is monophonic, it returns channel 0.

Lights representing polyphonic signals should display the “root mean sum” of the channels.

The root mean sum is defined as

\sqrt{x_0^2 + x_1^2 + x_2^2 + \ldots + x_n^2}

This formula returns 1 if any of the channels are 1, and it reduces to the identify function in the monophonic case.

VCV recommends to use blue for polyphonic signals, such as componentlibrary::SCHEME_BLUE.

8 Likes

I was not aware that monophonic modules have to sum the polyphonic signals, is this new?

Hi Omri, this is not new, it’s been in the manual for many months, but it’s probably not all developpers that implement those guidelines across all their modules. I tried to adhere to this, but I may have forgotten a few instances.

https://vcvrack.com/manual/VoltageStandards#polyphony

There is a problem with the max rule, in that it’s possible to create feedback paths, where the poly channel count can go up, but not back down, without restarting the patch.

Here is a trivial, contrived, example (it requires the latest Audible built from source) – here I’ve just set the poly channels on MIDI-CV to 8, then back to 4, but VIZ still shows 8:

Screen Shot 2020-04-23 at 6.13.21 PM

On my first version with poly support, I used the max approach as above with several modules. Then a user filed this bug, with a legitimate patch that demonstrates the feedback issue (again they had turned the channels up, then back down). At the time of the bug, both FM-OP and MATRIX88 set their output channels to the max of multiple inputs (V/OCT and GATE for FM-OP; any input for MATRIX88).

Wanting to make this problem go away forever, and being unaware of any standard at the time, I adopted the rule that no more than one input port defines the polyphony at any given time per module. This means different things for different modules. With FM-OP, I changed it to only define polyphony from V/OCT, because GATE didn’t really seem that useful. With MATRIX88, only the first input can define the polyphony. On my S&H, the default poly port is GATE, but it can be switched on the context menu to IN.

To be clear, other inputs process poly signals in the standard way (e.g. all inputs to MATRIX88 may be poly) – but only one port sets the channel count.

I get it that this is a weird problem that will affect almost no one, but thought I’d share my journey.

3 Likes

In my opinion, it is a higher probability for users to find benefit in multiple primary polyphonic inputs than for them to run into the polyphonic feedback problem you’re describing above.

I never heard this until now, but it makes sense. And, of course, no module “has” to do anything :wink: did modules ever “have” to have low cpu consumption? No, but it makes them more useful to people. In any case, this is a good tip.

1 Like

Ok. I’ve raised an issue on the developer’s git hub, because I’m pretty sure there are some Submarine modules that don’t do this.

I’ve slated it for the next release.

3 Likes

It has been in the standard since a few weeks after the Rack v1 source was released. However, I don’t expect all monophonic plugin developers to notice it, so the best we can do is remind them. It’s a fully backward compatible change.