Skip to content

Instantly share code, notes, and snippets.

@nick-thompson
Created July 13, 2018 22:16
Show Gist options
  • Save nick-thompson/b018a62bf73d84666a3895dc35b1f491 to your computer and use it in GitHub Desktop.
Save nick-thompson/b018a62bf73d84666a3895dc35b1f491 to your computer and use it in GitHub Desktop.
Modulation Matrix Implementation
template <int Rows, int Cols, typename FloatType>
class ModulationMatrix
{
public:
//==============================================================================
ModulationMatrix (std::array<std::array<FloatType*, Cols>, Rows> params) : m_rawMatrixParams(params) {}
~ModulationMatrix () {}
//==============================================================================
/** Returns the internal raw parameter matrix. */
auto getRawMatrixParameters() { return m_rawMatrixParams; }
/** Computes the aggregate modulation value for each target. */
template <unsigned long N, unsigned long M>
void tick (const std::array<FloatType, N> modValues, std::array<FloatType, M>& targetValues)
{
static_assert(N == Cols, "The number of modulation values received must equal the number of columsn.");
static_assert(M == Rows, "The number of target values received must equal the number of rows.");
// Reset target values to zero
targetValues.fill(static_cast<FloatType>(0.));
for (int i = 0; i < Rows; ++i)
{
// Accumulate the various modulation sources
for (int j = 0; j < Cols; ++j)
{
targetValues[i] += modValues[j] * (*m_rawMatrixParams[i][j]);
}
}
}
private:
//==============================================================================
std::array<std::array<FloatType*, Cols>, Rows> m_rawMatrixParams;
//==============================================================================
JUCE_LEAK_DETECTOR (ModulationMatrix)
};
// In your constructor, assuming AudioProcessorValueTreeState `m_state`
std::array<std::array<float*, NumSources>, NumTargets> rawMatrixParams;
for (int i = 0; i < ModulationTargets::NumTargets; ++i)
{
for (int j = 0; j < ModulationSources::NumSources; ++j)
{
String id = String("matrix/") + String(i) + String("/") + String(j);
m_state.createAndAddParameter(id, id, String(),
NormalisableRange<float>(0.f, 1.f), 0.f,
nullptr, nullptr);
rawMatrixParams[i][j] = m_state.getRawParameterValue(id);
}
}
// Assuming we'll process at least one channel, lets build the first modulation matrix.
// Note, this touches a member vector `std::vector<ci::ModulationMatrix<NumTargets, NumSources, float>> modMatrix;`
modMatrix.push_back(ci::ModulationMatrix<NumTargets, NumSources, float>(rawMatrixParams));
// Then in prepareToPlay, you can allocate 1 matrix per channel
jassert (modMatrix.size() > 0);
modMatrix.resize(numChannels, modMatrix[0].getRawMatrixParameters());
// And in processBlock, step each modulator and then step the matrix
float lfo1 = lfoMods[0].tick();
float lfo2 = lfoMods[1].tick();
float lfo3 = lfoMods[2].tick();
// Now step the modulation matrix, overwriting `matrixValues`.
const std::array<float, NumSources> modValues { lfo1, lfo2, lfo3 };
modMatrix[i].tick(modValues, matrixValues);
// Now `matrixValues` contains everything you need to apply to your parameters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment