Use the mod matrix in filters and eqs

This commit is contained in:
Paul Ferrand 2020-09-16 14:48:36 +02:00
parent 0f74039b39
commit f145481160
5 changed files with 78 additions and 54 deletions

View file

@ -4,7 +4,7 @@
#include "SIMDHelpers.h"
#include "SwapAndPop.h"
sfz::EQHolder::EQHolder(const Resources& resources)
sfz::EQHolder::EQHolder(Resources& resources)
: resources(resources)
{
eq = absl::make_unique<FilterEq>();
@ -46,45 +46,53 @@ void sfz::EQHolder::setup(const Region& region, unsigned eqId, float velocity)
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain);
gainTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqGain, region.id, eqId));
bandwidthTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqBandwidth, region.id, eqId));
frequencyTarget = resources.modMatrix.findTarget(ModKey::createNXYZ(ModId::EqFrequency, region.id, eqId));
// Initialize the EQ
DBG(baseFrequency << " " << baseBandwidth << " " << baseGain);
eq->prepare(lastFrequency, lastBandwidth, lastGain);
}
void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numFrames)
{
auto justCopy = [&]() {
if (description == nullptr) {
for (unsigned channelIdx = 0; channelIdx < eq->channels(); channelIdx++)
copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames });
};
if (description == nullptr) {
justCopy();
return;
}
// TODO: Once the midistate envelopes are done, add modulation in there!
// For now we take the last value
float lastFrequency = baseFrequency;
for (const auto& mod : description->frequencyCC)
lastFrequency += resources.midiState.getCCValue(mod.cc) * mod.data;
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
ModMatrix& mm = resources.modMatrix;
auto frequencySpan = resources.bufferPool.getBuffer(numFrames);
auto bandwidthSpan = resources.bufferPool.getBuffer(numFrames);
auto gainSpan = resources.bufferPool.getBuffer(numFrames);
float lastBandwidth = baseBandwidth;
for (const auto& mod : description->bandwidthCC)
lastBandwidth += resources.midiState.getCCValue(mod.cc) * mod.data;
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
float lastGain = baseGain;
for (const auto& mod : description->gainCC)
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain);
if (lastGain == 0.0f) {
justCopy();
if (!frequencySpan || !bandwidthSpan || !gainSpan)
return;
}
eq->process(inputs, outputs, lastFrequency, lastBandwidth, lastGain, numFrames);
fill<float>(*frequencySpan, baseFrequency);
if (float* mod = mm.getModulation(frequencyTarget))
add<float>(absl::Span<float>(mod, numFrames), *frequencySpan);
fill<float>(*bandwidthSpan, baseBandwidth);
if (float* mod = mm.getModulation(bandwidthTarget))
add<float>(absl::Span<float>(mod, numFrames), *bandwidthSpan);
fill<float>(*gainSpan, baseGain);
if (float* mod = mm.getModulation(gainTarget))
add<float>(absl::Span<float>(mod, numFrames), *gainSpan);
DBG(frequencySpan->back() << " " << bandwidthSpan->back() << " " << gainSpan->back());
eq->processModulated(
inputs,
outputs,
frequencySpan->data(),
bandwidthSpan->data(),
gainSpan->data(),
numFrames
);
}
void sfz::EQHolder::setSampleRate(float sampleRate)

View file

@ -14,7 +14,7 @@ class EQHolder
{
public:
EQHolder() = delete;
EQHolder(const Resources& resources);
EQHolder(Resources& resources);
/**
* @brief Setup a new EQ from a region and an index
*
@ -42,15 +42,15 @@ public:
*/
void reset();
private:
const Resources& resources;
Resources& resources;
const EQDescription* description;
std::unique_ptr<FilterEq> eq;
float baseBandwidth { Default::eqBandwidth };
float baseFrequency { Default::eqFrequency1 };
float baseGain { Default::eqGain };
ModMatrix::TargetId eqGainTarget;
ModMatrix::TargetId eqFrequencyTarget;
ModMatrix::TargetId eqBandwidthTarget;
ModMatrix::TargetId gainTarget;
ModMatrix::TargetId frequencyTarget;
ModMatrix::TargetId bandwidthTarget;
};
}

View file

@ -5,7 +5,7 @@
#include <thread>
#include <chrono>
sfz::FilterHolder::FilterHolder(const Resources& resources)
sfz::FilterHolder::FilterHolder(Resources& resources)
: resources(resources)
{
filter = absl::make_unique<Filter>();
@ -57,6 +57,11 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain);
ModMatrix& mm = resources.modMatrix;
gainTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilGain, region.id, filterId));
cutoffTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilCutoff, region.id, filterId));
resonanceTarget = mm.findTarget(ModKey::createNXYZ(ModId::FilResonance, region.id, filterId));
// Initialize the filter
filter->prepare(lastCutoff, lastResonance, lastGain);
}
@ -69,25 +74,36 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
return;
}
// TODO: Once the midistate envelopes are done, add modulation in there!
// For now we take the last value
// TODO: the template deduction could be automatic here?
float lastCutoff = baseCutoff;
for (const auto& mod : description->cutoffCC)
lastCutoff *= centsFactor(resources.midiState.getCCValue(mod.cc) * mod.data);
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
ModMatrix& mm = resources.modMatrix;
auto cutoffSpan = resources.bufferPool.getBuffer(numFrames);
auto resonanceSpan = resources.bufferPool.getBuffer(numFrames);
auto gainSpan = resources.bufferPool.getBuffer(numFrames);
float lastResonance = baseResonance;
for (const auto& mod : description->resonanceCC)
lastResonance += resources.midiState.getCCValue(mod.cc) * mod.data;
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
if (!cutoffSpan || !resonanceSpan || !gainSpan)
return;
float lastGain = baseGain;
for (const auto& mod : description->gainCC)
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain);
fill<float>(*cutoffSpan, baseCutoff);
if (float* mod = mm.getModulation(cutoffTarget)) {
for (size_t i = 0; i < numFrames; ++i)
(*cutoffSpan)[i] *= centsFactor(mod[i]);
}
filter->process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames);
fill<float>(*resonanceSpan, baseResonance);
if (float* mod = mm.getModulation(resonanceTarget))
add<float>(absl::Span<float>(mod, numFrames), *resonanceSpan);
fill<float>(*gainSpan, baseGain);
if (float* mod = mm.getModulation(gainTarget))
add<float>(absl::Span<float>(mod, numFrames), *gainSpan);
filter->processModulated(
inputs,
outputs,
cutoffSpan->data(),
resonanceSpan->data(),
gainSpan->data(),
numFrames
);
}

View file

@ -15,7 +15,7 @@ class FilterHolder
{
public:
FilterHolder() = delete;
FilterHolder(const Resources& resources);
FilterHolder(Resources& resources);
/**
* @brief Setup a new filter based on a filter description, and a triggering note parameters.
*
@ -44,15 +44,15 @@ public:
*/
void reset();
private:
const Resources& resources;
Resources& resources;
const FilterDescription* description;
std::unique_ptr<Filter> filter;
float baseCutoff { Default::filterCutoff };
float baseResonance { Default::filterResonance };
float baseGain { Default::filterGain };
ModMatrix::TargetId filterGainTarget;
ModMatrix::TargetId filterCutoffTarget;
ModMatrix::TargetId filterResonanceTarget;
ModMatrix::TargetId gainTarget;
ModMatrix::TargetId cutoffTarget;
ModMatrix::TargetId resonanceTarget;
using filterRandomDist = std::uniform_int_distribution<int>;
filterRandomDist dist { 0, sfz::Default::filterRandom };
};

View file

@ -49,7 +49,7 @@ int ModIds::flags(ModId id) noexcept
case ModId::FilCutoff:
return kModIsPerVoice|kModIsAdditive;
case ModId::FilResonance:
return kModIsPerVoice|kModIsMultiplicative;
return kModIsPerVoice|kModIsAdditive;
case ModId::EqGain:
return kModIsPerVoice|kModIsAdditive;
case ModId::EqFrequency: