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 "SIMDHelpers.h"
#include "SwapAndPop.h" #include "SwapAndPop.h"
sfz::EQHolder::EQHolder(const Resources& resources) sfz::EQHolder::EQHolder(Resources& resources)
: resources(resources) : resources(resources)
{ {
eq = absl::make_unique<FilterEq>(); 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 += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); 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 // Initialize the EQ
DBG(baseFrequency << " " << baseBandwidth << " " << baseGain);
eq->prepare(lastFrequency, lastBandwidth, lastGain); eq->prepare(lastFrequency, lastBandwidth, lastGain);
} }
void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numFrames) void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numFrames)
{ {
auto justCopy = [&]() { if (description == nullptr) {
for (unsigned channelIdx = 0; channelIdx < eq->channels(); channelIdx++) for (unsigned channelIdx = 0; channelIdx < eq->channels(); channelIdx++)
copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames }); copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames });
};
if (description == nullptr) {
justCopy();
return; return;
} }
// TODO: Once the midistate envelopes are done, add modulation in there! ModMatrix& mm = resources.modMatrix;
// For now we take the last value auto frequencySpan = resources.bufferPool.getBuffer(numFrames);
float lastFrequency = baseFrequency; auto bandwidthSpan = resources.bufferPool.getBuffer(numFrames);
for (const auto& mod : description->frequencyCC) auto gainSpan = resources.bufferPool.getBuffer(numFrames);
lastFrequency += resources.midiState.getCCValue(mod.cc) * mod.data;
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
float lastBandwidth = baseBandwidth; if (!frequencySpan || !bandwidthSpan || !gainSpan)
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();
return; 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) void sfz::EQHolder::setSampleRate(float sampleRate)

View file

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

View file

@ -5,7 +5,7 @@
#include <thread> #include <thread>
#include <chrono> #include <chrono>
sfz::FilterHolder::FilterHolder(const Resources& resources) sfz::FilterHolder::FilterHolder(Resources& resources)
: resources(resources) : resources(resources)
{ {
filter = absl::make_unique<Filter>(); 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 += resources.midiState.getCCValue(mod.cc) * mod.data;
lastGain = Default::filterGainRange.clamp(lastGain); 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 // Initialize the filter
filter->prepare(lastCutoff, lastResonance, lastGain); filter->prepare(lastCutoff, lastResonance, lastGain);
} }
@ -69,25 +74,36 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
return; return;
} }
// TODO: Once the midistate envelopes are done, add modulation in there! ModMatrix& mm = resources.modMatrix;
// For now we take the last value auto cutoffSpan = resources.bufferPool.getBuffer(numFrames);
// TODO: the template deduction could be automatic here? auto resonanceSpan = resources.bufferPool.getBuffer(numFrames);
float lastCutoff = baseCutoff; auto gainSpan = resources.bufferPool.getBuffer(numFrames);
for (const auto& mod : description->cutoffCC)
lastCutoff *= centsFactor(resources.midiState.getCCValue(mod.cc) * mod.data);
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
float lastResonance = baseResonance; if (!cutoffSpan || !resonanceSpan || !gainSpan)
for (const auto& mod : description->resonanceCC) return;
lastResonance += resources.midiState.getCCValue(mod.cc) * mod.data;
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
float lastGain = baseGain; fill<float>(*cutoffSpan, baseCutoff);
for (const auto& mod : description->gainCC) if (float* mod = mm.getModulation(cutoffTarget)) {
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data; for (size_t i = 0; i < numFrames; ++i)
lastGain = Default::filterGainRange.clamp(lastGain); (*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: public:
FilterHolder() = delete; FilterHolder() = delete;
FilterHolder(const Resources& resources); FilterHolder(Resources& resources);
/** /**
* @brief Setup a new filter based on a filter description, and a triggering note parameters. * @brief Setup a new filter based on a filter description, and a triggering note parameters.
* *
@ -44,15 +44,15 @@ public:
*/ */
void reset(); void reset();
private: private:
const Resources& resources; Resources& resources;
const FilterDescription* description; const FilterDescription* description;
std::unique_ptr<Filter> filter; std::unique_ptr<Filter> filter;
float baseCutoff { Default::filterCutoff }; float baseCutoff { Default::filterCutoff };
float baseResonance { Default::filterResonance }; float baseResonance { Default::filterResonance };
float baseGain { Default::filterGain }; float baseGain { Default::filterGain };
ModMatrix::TargetId filterGainTarget; ModMatrix::TargetId gainTarget;
ModMatrix::TargetId filterCutoffTarget; ModMatrix::TargetId cutoffTarget;
ModMatrix::TargetId filterResonanceTarget; ModMatrix::TargetId resonanceTarget;
using filterRandomDist = std::uniform_int_distribution<int>; using filterRandomDist = std::uniform_int_distribution<int>;
filterRandomDist dist { 0, sfz::Default::filterRandom }; filterRandomDist dist { 0, sfz::Default::filterRandom };
}; };

View file

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