Use the mod matrix in filters and eqs
This commit is contained in:
parent
0f74039b39
commit
f145481160
5 changed files with 78 additions and 54 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue