I’m also curious about this issue, and I’d be curious to know what is considered the “best practice”.
Should it be as follows ?
- Use an AudioProcessorValueTreeState for external parameters
- Link those parameters (and maybe other internal variables?) to a “ModMatrix” class, as “modulation destinations”
- Link your LFOs, Enveloppes, etc. as “modulation sources”. Create a ModulationSource class to inherit from
- Add a ModMatrix.getValues(parameter) function, to get the computed values of your modulated parameter, for the current block
- Add a ModMatrix.link(parameter, source, modulationDepth, modulationPolarity) function
- Store all computed values in AudioBuffers, for flexible, audio-rate modulations operations
I assume getValues(parameter) should work in a way akin to the following ( I’m very new to C++ and JUCE, so bear with me).
AudioBuffer ModMatrix::getValues (String ¶meterID, int samplesPerBlock)
AudioBuffer values = new AudioBuffer (1, samplesPerBlock); // 1 channel
for (ModulationSource modSource : modSources)
AudioBuffer sourceValues = modSource.computeValues(samplesPerBlock);
values.addFrom (0, 0, sourceValues, samplesPerBlock, modSource.getModulationDepth());
Is that somewhat correct, or is this far fetched ?