Remove the EQ/Filter pools
Voices hold their own tentative eq and filters that get initialized upon starting the voice depending on how many there are in the region
This commit is contained in:
parent
4e58a945a8
commit
dc4f59107b
7 changed files with 111 additions and 361 deletions
|
|
@ -4,22 +4,23 @@
|
|||
#include "SIMDHelpers.h"
|
||||
#include "SwapAndPop.h"
|
||||
|
||||
sfz::EQHolder::EQHolder(const MidiState& state)
|
||||
:midiState(state)
|
||||
sfz::EQHolder::EQHolder(const Resources& resources)
|
||||
: resources(resources)
|
||||
{
|
||||
|
||||
eq = absl::make_unique<FilterEq>();
|
||||
eq->init(config::defaultSampleRate);
|
||||
}
|
||||
|
||||
void sfz::EQHolder::reset()
|
||||
{
|
||||
eq.clear();
|
||||
eq->clear();
|
||||
}
|
||||
|
||||
void sfz::EQHolder::setup(const EQDescription& description, unsigned numChannels, float velocity)
|
||||
{
|
||||
ASSERT(velocity >= 0.0f && velocity <= 1.0f);
|
||||
eq.setType(description.type);
|
||||
eq.setChannels(numChannels);
|
||||
eq->setType(description.type);
|
||||
eq->setChannels(numChannels);
|
||||
this->description = &description;
|
||||
|
||||
// Setup the base values
|
||||
|
|
@ -28,29 +29,29 @@ void sfz::EQHolder::setup(const EQDescription& description, unsigned numChannels
|
|||
baseGain = description.gain + velocity * description.vel2gain;
|
||||
|
||||
// Setup the modulated values
|
||||
lastFrequency = baseFrequency;
|
||||
float lastFrequency = baseFrequency;
|
||||
for (const auto& mod : description.frequencyCC)
|
||||
lastFrequency += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastFrequency += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
|
||||
|
||||
lastBandwidth = baseBandwidth;
|
||||
float lastBandwidth = baseBandwidth;
|
||||
for (const auto& mod : description.bandwidthCC)
|
||||
lastBandwidth += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastBandwidth += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
|
||||
|
||||
lastGain = baseGain;
|
||||
float lastGain = baseGain;
|
||||
for (const auto& mod : description.gainCC)
|
||||
lastGain += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
// Initialize the EQ
|
||||
eq.prepare(lastFrequency, lastBandwidth, lastGain);
|
||||
eq->prepare(lastFrequency, lastBandwidth, lastGain);
|
||||
}
|
||||
|
||||
void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numFrames)
|
||||
{
|
||||
auto justCopy = [&]() {
|
||||
for (unsigned channelIdx = 0; channelIdx < eq.channels(); channelIdx++)
|
||||
for (unsigned channelIdx = 0; channelIdx < eq->channels(); channelIdx++)
|
||||
copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames });
|
||||
};
|
||||
|
||||
|
|
@ -61,19 +62,19 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF
|
|||
|
||||
// TODO: Once the midistate envelopes are done, add modulation in there!
|
||||
// For now we take the last value
|
||||
lastFrequency = baseFrequency;
|
||||
float lastFrequency = baseFrequency;
|
||||
for (const auto& mod : description->frequencyCC)
|
||||
lastFrequency += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastFrequency += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastFrequency = Default::eqFrequencyRange.clamp(lastFrequency);
|
||||
|
||||
lastBandwidth = baseBandwidth;
|
||||
float lastBandwidth = baseBandwidth;
|
||||
for (const auto& mod : description->bandwidthCC)
|
||||
lastBandwidth += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastBandwidth += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastBandwidth = Default::eqBandwidthRange.clamp(lastBandwidth);
|
||||
|
||||
lastGain = baseGain;
|
||||
float lastGain = baseGain;
|
||||
for (const auto& mod : description->gainCC)
|
||||
lastGain += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
if (lastGain == 0.0f) {
|
||||
|
|
@ -81,70 +82,10 @@ void sfz::EQHolder::process(const float** inputs, float** outputs, unsigned numF
|
|||
return;
|
||||
}
|
||||
|
||||
eq.process(inputs, outputs, lastFrequency, lastBandwidth, lastGain, numFrames);
|
||||
}
|
||||
float sfz::EQHolder::getLastFrequency() const
|
||||
{
|
||||
return lastFrequency;
|
||||
}
|
||||
float sfz::EQHolder::getLastBandwidth() const
|
||||
{
|
||||
return lastBandwidth;
|
||||
}
|
||||
float sfz::EQHolder::getLastGain() const
|
||||
{
|
||||
return lastGain;
|
||||
eq->process(inputs, outputs, lastFrequency, lastBandwidth, lastGain, numFrames);
|
||||
}
|
||||
|
||||
void sfz::EQHolder::setSampleRate(float sampleRate)
|
||||
{
|
||||
eq.init(static_cast<double>(sampleRate));
|
||||
}
|
||||
|
||||
sfz::EQPool::EQPool(const MidiState& state, int numEQs)
|
||||
: midiState(state)
|
||||
{
|
||||
setnumEQs(numEQs);
|
||||
}
|
||||
|
||||
sfz::EQHolderPtr sfz::EQPool::getEQ(const EQDescription& description, unsigned numChannels, float velocity)
|
||||
{
|
||||
const std::unique_lock<SpinMutex> lock { eqGuard, std::try_to_lock };
|
||||
if (!lock.owns_lock())
|
||||
return {};
|
||||
|
||||
auto eq = absl::c_find_if(eqs, [](const EQHolderPtr& holder) {
|
||||
return holder.use_count() == 1;
|
||||
});
|
||||
|
||||
if (eq == eqs.end())
|
||||
return {};
|
||||
|
||||
(**eq).setup(description, numChannels, velocity);
|
||||
return *eq;
|
||||
}
|
||||
|
||||
size_t sfz::EQPool::getActiveEQs() const
|
||||
{
|
||||
return absl::c_count_if(eqs, [](const EQHolderPtr& holder) {
|
||||
return holder.use_count() > 1;
|
||||
});
|
||||
}
|
||||
|
||||
size_t sfz::EQPool::setnumEQs(size_t numEQs)
|
||||
{
|
||||
const std::lock_guard<SpinMutex> eqLock { eqGuard };
|
||||
|
||||
swapAndPopAll(eqs, [](sfz::EQHolderPtr& eq) { return eq.use_count() == 1; });
|
||||
|
||||
for (size_t i = eqs.size(); i < numEQs; ++i) {
|
||||
eqs.emplace_back(std::make_shared<EQHolder>(midiState));
|
||||
eqs.back()->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
return eqs.size();
|
||||
}
|
||||
void sfz::EQPool::setSampleRate(float sampleRate)
|
||||
{
|
||||
for (auto& eq: eqs)
|
||||
eq->setSampleRate(sampleRate);
|
||||
eq->init(static_cast<double>(sampleRate));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "SfzFilter.h"
|
||||
#include "EQDescription.h"
|
||||
#include "MidiState.h"
|
||||
#include "Resources.h"
|
||||
#include "utility/SpinMutex.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
|
@ -14,7 +14,7 @@ class EQHolder
|
|||
{
|
||||
public:
|
||||
EQHolder() = delete;
|
||||
EQHolder(const MidiState& state);
|
||||
EQHolder(const Resources& resources);
|
||||
/**
|
||||
* @brief Setup a new EQ based on an EQ description.
|
||||
*
|
||||
|
|
@ -31,94 +31,26 @@ public:
|
|||
* @param numFrames
|
||||
*/
|
||||
void process(const float** inputs, float** outputs, unsigned numFrames);
|
||||
/**
|
||||
* @brief Returns the last value of the frequency for the EQ
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastFrequency() const;
|
||||
/**
|
||||
* @brief Returns the last value of the bandwitdh for the EQ
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastBandwidth() const;
|
||||
/**
|
||||
* @brief Returns the last value of the gain for the EQ
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastGain() const;
|
||||
/**
|
||||
* @brief Set the sample rate for the EQ
|
||||
*
|
||||
* @param sampleRate
|
||||
*/
|
||||
void setSampleRate(float sampleRate);
|
||||
private:
|
||||
/**
|
||||
* Reset the filter. Is called internally when using setup().
|
||||
* Reset the filter.
|
||||
*/
|
||||
void reset();
|
||||
const MidiState& midiState;
|
||||
private:
|
||||
const Resources& resources;
|
||||
const EQDescription* description;
|
||||
FilterEq eq;
|
||||
std::unique_ptr<FilterEq> eq;
|
||||
float baseBandwidth { Default::eqBandwidth };
|
||||
float baseFrequency { Default::eqFrequency1 };
|
||||
float baseGain { Default::eqGain };
|
||||
float lastBandwidth { Default::eqBandwidth };
|
||||
float lastFrequency { Default::eqFrequency1 };
|
||||
float lastGain { Default::eqGain };
|
||||
ModMatrix::TargetId eqGainTarget;
|
||||
ModMatrix::TargetId eqFrequencyTarget;
|
||||
ModMatrix::TargetId eqBandwidthTarget;
|
||||
};
|
||||
|
||||
using EQHolderPtr = std::shared_ptr<EQHolder>;
|
||||
|
||||
class EQPool
|
||||
{
|
||||
public:
|
||||
EQPool() = delete;
|
||||
/**
|
||||
* @brief Construct a new EQPool object
|
||||
*
|
||||
* @param state the associated midi state
|
||||
* @param numEQs the number of inactive EQs to hold in the pool
|
||||
*/
|
||||
EQPool(const MidiState& state, int numEQs = config::filtersInPool);
|
||||
/**
|
||||
* @brief Get an EQ object to use in Voices
|
||||
*
|
||||
* @param description the filter description to bind to the EQ
|
||||
* @param numChannels the number of channels for the EQ
|
||||
* @param velocity the triggering note velocity/value
|
||||
* @return EQHolderPtr release this when done with the filter; no deallocation will be done
|
||||
*/
|
||||
EQHolderPtr getEQ(const EQDescription& description, unsigned numChannels, float velocity);
|
||||
/**
|
||||
* @brief Get the number of active EQs
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getActiveEQs() const;
|
||||
/**
|
||||
* @brief Set the number of EQs in the pool. This function may sleep and should be called from a background thread.
|
||||
* No EQs will be distributed during the reallocation of EQs. Existing running EQs are kept. If the target
|
||||
* number of EQs is less that the number of active EQs, the function will not remove them and you may need
|
||||
* to call it again after existing EQs have run out.
|
||||
*
|
||||
* @param numEQs
|
||||
* @return size_t the actual number of EQs in the pool
|
||||
*/
|
||||
size_t setnumEQs(size_t numEQs);
|
||||
/**
|
||||
* @brief Set the sample rate for all EQs
|
||||
*
|
||||
* @param sampleRate
|
||||
*/
|
||||
void setSampleRate(float sampleRate);
|
||||
private:
|
||||
SpinMutex eqGuard;
|
||||
float sampleRate { config::defaultSampleRate };
|
||||
const MidiState& midiState;
|
||||
std::vector<EQHolderPtr> eqs;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,16 @@
|
|||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
sfz::FilterHolder::FilterHolder(const MidiState& midiState)
|
||||
: midiState(midiState)
|
||||
sfz::FilterHolder::FilterHolder(const Resources& resources)
|
||||
: resources(resources)
|
||||
{
|
||||
|
||||
filter = absl::make_unique<Filter>();
|
||||
filter->init(config::defaultSampleRate);
|
||||
}
|
||||
|
||||
void sfz::FilterHolder::reset()
|
||||
{
|
||||
filter.clear();
|
||||
filter->clear();
|
||||
}
|
||||
|
||||
void sfz::FilterHolder::setup(const FilterDescription& description, unsigned numChannels, int noteNumber, float velocity)
|
||||
|
|
@ -21,8 +22,8 @@ void sfz::FilterHolder::setup(const FilterDescription& description, unsigned num
|
|||
ASSERT(velocity >= 0.0f && velocity <= 1.0f);
|
||||
|
||||
this->description = &description;
|
||||
filter.setType(description.type);
|
||||
filter.setChannels(numChannels);
|
||||
filter->setType(description.type);
|
||||
filter->setChannels(numChannels);
|
||||
|
||||
// Setup the base values
|
||||
baseCutoff = description.cutoff;
|
||||
|
|
@ -40,29 +41,29 @@ void sfz::FilterHolder::setup(const FilterDescription& description, unsigned num
|
|||
baseResonance = description.resonance;
|
||||
|
||||
// Setup the modulated values
|
||||
lastCutoff = baseCutoff;
|
||||
float lastCutoff = baseCutoff;
|
||||
for (const auto& mod : description.cutoffCC)
|
||||
lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.data);
|
||||
lastCutoff *= centsFactor(resources.midiState.getCCValue(mod.cc) * mod.data);
|
||||
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
|
||||
|
||||
lastResonance = baseResonance;
|
||||
float lastResonance = baseResonance;
|
||||
for (const auto& mod : description.resonanceCC)
|
||||
lastResonance += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastResonance += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
|
||||
|
||||
lastGain = baseGain;
|
||||
float lastGain = baseGain;
|
||||
for (const auto& mod : description.gainCC)
|
||||
lastGain += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
// Initialize the filter
|
||||
filter.prepare(lastCutoff, lastResonance, lastGain);
|
||||
filter->prepare(lastCutoff, lastResonance, lastGain);
|
||||
}
|
||||
|
||||
void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned numFrames)
|
||||
{
|
||||
if (description == nullptr) {
|
||||
for (unsigned channelIdx = 0; channelIdx < filter.channels(); channelIdx++)
|
||||
for (unsigned channelIdx = 0; channelIdx < filter->channels(); channelIdx++)
|
||||
copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames });
|
||||
return;
|
||||
}
|
||||
|
|
@ -70,88 +71,26 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
|
|||
// 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?
|
||||
lastCutoff = baseCutoff;
|
||||
float lastCutoff = baseCutoff;
|
||||
for (const auto& mod : description->cutoffCC)
|
||||
lastCutoff *= centsFactor(midiState.getCCValue(mod.cc) * mod.data);
|
||||
lastCutoff *= centsFactor(resources.midiState.getCCValue(mod.cc) * mod.data);
|
||||
lastCutoff = Default::filterCutoffRange.clamp(lastCutoff);
|
||||
|
||||
lastResonance = baseResonance;
|
||||
float lastResonance = baseResonance;
|
||||
for (const auto& mod : description->resonanceCC)
|
||||
lastResonance += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastResonance += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastResonance = Default::filterResonanceRange.clamp(lastResonance);
|
||||
|
||||
lastGain = baseGain;
|
||||
float lastGain = baseGain;
|
||||
for (const auto& mod : description->gainCC)
|
||||
lastGain += midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain += resources.midiState.getCCValue(mod.cc) * mod.data;
|
||||
lastGain = Default::filterGainRange.clamp(lastGain);
|
||||
|
||||
filter.process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames);
|
||||
filter->process(inputs, outputs, lastCutoff, lastResonance, lastGain, numFrames);
|
||||
}
|
||||
|
||||
float sfz::FilterHolder::getLastCutoff() const
|
||||
{
|
||||
return lastCutoff;
|
||||
}
|
||||
float sfz::FilterHolder::getLastResonance() const
|
||||
{
|
||||
return lastResonance;
|
||||
}
|
||||
float sfz::FilterHolder::getLastGain() const
|
||||
{
|
||||
return lastGain;
|
||||
}
|
||||
|
||||
sfz::FilterPool::FilterPool(const MidiState& state, int numFilters)
|
||||
: midiState(state)
|
||||
{
|
||||
setNumFilters(numFilters);
|
||||
}
|
||||
|
||||
sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& description, unsigned numChannels, int noteNumber, float velocity)
|
||||
{
|
||||
const std::unique_lock<SpinMutex> lock { filterGuard, std::try_to_lock };
|
||||
if (!lock.owns_lock())
|
||||
return {};
|
||||
|
||||
auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) {
|
||||
return holder.use_count() == 1;
|
||||
});
|
||||
|
||||
if (filter == filters.end())
|
||||
return {};
|
||||
|
||||
(**filter).setup(description, numChannels, noteNumber, velocity);
|
||||
return *filter;
|
||||
}
|
||||
|
||||
size_t sfz::FilterPool::getActiveFilters() const
|
||||
{
|
||||
return absl::c_count_if(filters, [](const FilterHolderPtr& holder) {
|
||||
return holder.use_count() > 1;
|
||||
});
|
||||
}
|
||||
|
||||
size_t sfz::FilterPool::setNumFilters(size_t numFilters)
|
||||
{
|
||||
const std::lock_guard<SpinMutex> filterLock { filterGuard };
|
||||
|
||||
swapAndPopAll(filters, [](sfz::FilterHolderPtr& filter) { return filter.use_count() == 1; });
|
||||
|
||||
for (size_t i = filters.size(); i < numFilters; ++i) {
|
||||
filters.emplace_back(std::make_shared<FilterHolder>(midiState));
|
||||
filters.back()->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
return filters.size();
|
||||
}
|
||||
|
||||
void sfz::FilterPool::setSampleRate(float sampleRate)
|
||||
{
|
||||
for (auto& filter: filters)
|
||||
filter->setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
void sfz::FilterHolder::setSampleRate(float sampleRate)
|
||||
{
|
||||
filter.init(static_cast<double>(sampleRate));
|
||||
filter->init(static_cast<double>(sampleRate));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include "SfzFilter.h"
|
||||
#include "FilterDescription.h"
|
||||
#include "MidiState.h"
|
||||
#include "Resources.h"
|
||||
#include "Defaults.h"
|
||||
#include "utility/SpinMutex.h"
|
||||
#include <vector>
|
||||
|
|
@ -15,7 +15,7 @@ class FilterHolder
|
|||
{
|
||||
public:
|
||||
FilterHolder() = delete;
|
||||
FilterHolder(const MidiState& state);
|
||||
FilterHolder(const Resources& resources);
|
||||
/**
|
||||
* @brief Setup a new filter based on a filter description, and a triggering note parameters.
|
||||
*
|
||||
|
|
@ -33,97 +33,28 @@ public:
|
|||
* @param numFrames
|
||||
*/
|
||||
void process(const float** inputs, float** outputs, unsigned numFrames);
|
||||
/**
|
||||
* @brief Returns the last value of the cutoff for the filter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastCutoff() const;
|
||||
/**
|
||||
* @brief Returns the last value of the resonance for the filter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastResonance() const;
|
||||
/**
|
||||
* @brief Returns the last value of the gain for the filter
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
float getLastGain() const;
|
||||
/**
|
||||
* @brief Set the sample rate for a filter
|
||||
*
|
||||
* @param sampleRate
|
||||
*/
|
||||
void setSampleRate(float sampleRate);
|
||||
private:
|
||||
/**
|
||||
* Reset the filter. Is called internally when using setup().
|
||||
* Reset the filter.
|
||||
*/
|
||||
void reset();
|
||||
const MidiState& midiState;
|
||||
private:
|
||||
const Resources& resources;
|
||||
const FilterDescription* description;
|
||||
Filter filter;
|
||||
std::unique_ptr<Filter> filter;
|
||||
float baseCutoff { Default::filterCutoff };
|
||||
float baseResonance { Default::filterResonance };
|
||||
float baseGain { Default::filterGain };
|
||||
float lastCutoff { Default::filterCutoff };
|
||||
float lastResonance { Default::filterResonance };
|
||||
float lastGain { Default::filterGain };
|
||||
ModMatrix::TargetId filterGainTarget;
|
||||
ModMatrix::TargetId filterCutoffTarget;
|
||||
ModMatrix::TargetId filterResonanceTarget;
|
||||
using filterRandomDist = std::uniform_int_distribution<int>;
|
||||
filterRandomDist dist { 0, sfz::Default::filterRandom };
|
||||
};
|
||||
|
||||
using FilterHolderPtr = std::shared_ptr<FilterHolder>;
|
||||
|
||||
class FilterPool
|
||||
{
|
||||
public:
|
||||
FilterPool() = delete;
|
||||
/**
|
||||
* @brief Construct a new Filter Pool object
|
||||
*
|
||||
* @param state the associated midi state
|
||||
* @param numFilters the number of inactive filters to hold in the pool
|
||||
*/
|
||||
FilterPool(const MidiState& state, int numFilters = config::filtersInPool);
|
||||
/**
|
||||
* @brief Get a filter object to use in Voices
|
||||
*
|
||||
* @param description the filter description to bind to the filter
|
||||
* @param numChannels the number of channels in the underlying filter
|
||||
* @param noteNumber the triggering note number
|
||||
* @param velocity the triggering note velocity
|
||||
* @return FilterHolderPtr release this when done with the filter; no deallocation will be done
|
||||
*/
|
||||
FilterHolderPtr getFilter(const FilterDescription& description, unsigned numChannels, int noteNumber = static_cast<int>(Default::filterKeycenter), float velocity = 0);
|
||||
/**
|
||||
* @brief Get the number of active filters
|
||||
*
|
||||
* @return size_t
|
||||
*/
|
||||
size_t getActiveFilters() const;
|
||||
/**
|
||||
* @brief Set the number of filters in the pool. This function may sleep and should be called from a background thread.
|
||||
* No filters will be distributed during the reallocation of filters. Existing running filters are kept. If the target
|
||||
* number of filters is less that the number of active filters, the function will not remove them and you may need
|
||||
* to call it again after existing filters have run out.
|
||||
*
|
||||
* @param numFilters
|
||||
* @return size_t the actual number of filters in the pool
|
||||
*/
|
||||
size_t setNumFilters(size_t numFilters);
|
||||
/**
|
||||
* @brief Set the sample rate for all filters
|
||||
*
|
||||
* @param sampleRate
|
||||
*/
|
||||
void setSampleRate(float sampleRate);
|
||||
private:
|
||||
SpinMutex filterGuard;
|
||||
float sampleRate { config::defaultSampleRate };
|
||||
const MidiState& midiState;
|
||||
std::vector<FilterHolderPtr> filters;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
#include "SynthConfig.h"
|
||||
#include "MidiState.h"
|
||||
#include "FilePool.h"
|
||||
#include "BufferPool.h"
|
||||
#include "FilterPool.h"
|
||||
#include "EQPool.h"
|
||||
#include "Logger.h"
|
||||
#include "Wavetables.h"
|
||||
#include "Curve.h"
|
||||
|
|
@ -29,8 +28,6 @@ struct Resources
|
|||
Logger logger;
|
||||
CurveSet curves;
|
||||
FilePool filePool { logger };
|
||||
FilterPool filterPool { midiState };
|
||||
EQPool eqPool { midiState };
|
||||
WavetablePool wavePool;
|
||||
Tuning tuning;
|
||||
absl::optional<StretchTuning> stretch;
|
||||
|
|
@ -39,8 +36,6 @@ struct Resources
|
|||
void setSampleRate(float samplerate)
|
||||
{
|
||||
midiState.setSampleRate(samplerate);
|
||||
filterPool.setSampleRate(samplerate);
|
||||
eqPool.setSampleRate(samplerate);
|
||||
modMatrix.setSampleRate(samplerate);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,11 @@
|
|||
sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources)
|
||||
: id{voiceNumber}, stateListener(nullptr), resources(resources)
|
||||
{
|
||||
filters.reserve(config::filtersPerVoice);
|
||||
equalizers.reserve(config::eqsPerVoice);
|
||||
for (unsigned i = 0; i < config::filtersPerVoice; ++i)
|
||||
filters.emplace_back(resources);
|
||||
|
||||
for (unsigned i = 0; i < config::eqsPerVoice; ++i)
|
||||
equalizers.emplace_back(resources);
|
||||
|
||||
for (WavetableOscillator& osc : waveOscillators)
|
||||
osc.init(sampleRate);
|
||||
|
|
@ -118,21 +121,13 @@ void sfz::Voice::startVoice(Region* region, int delay, const TriggerEvent& event
|
|||
gainSmoother.reset();
|
||||
resetCrossfades();
|
||||
|
||||
// Check that we can handle the number of filters; filters should be cleared here
|
||||
ASSERT((filters.capacity() - filters.size()) >= region->filters.size());
|
||||
ASSERT((equalizers.capacity() - equalizers.size()) >= region->equalizers.size());
|
||||
|
||||
const unsigned numChannels = region->isStereo() ? 2 : 1;
|
||||
for (auto& filter: region->filters) {
|
||||
auto newFilter = resources.filterPool.getFilter(filter, numChannels, triggerEvent.number, triggerEvent.value);
|
||||
if (newFilter)
|
||||
filters.push_back(newFilter);
|
||||
for (unsigned i = 0; i < region->filters.size(); ++i) {
|
||||
filters[i].setup(region->filters[i], numChannels, triggerEvent.number, triggerEvent.value);
|
||||
}
|
||||
|
||||
for (auto& eq: region->equalizers) {
|
||||
auto newEQ = resources.eqPool.getEQ(eq, numChannels, triggerEvent.value);
|
||||
if (newEQ)
|
||||
equalizers.push_back(newEQ);
|
||||
for (unsigned i = 0; i < region->equalizers.size(); ++i) {
|
||||
equalizers[i].setup(region->equalizers[i], numChannels, triggerEvent.value);
|
||||
}
|
||||
|
||||
sourcePosition = region->getOffset();
|
||||
|
|
@ -253,6 +248,12 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept
|
|||
for (auto& lfo : lfos)
|
||||
lfo->setSampleRate(sampleRate);
|
||||
|
||||
for (auto& filter : filters)
|
||||
filter.setSampleRate(sampleRate);
|
||||
|
||||
for (auto& eq : equalizers)
|
||||
eq.setSampleRate(sampleRate);
|
||||
|
||||
powerFollower.setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
|
|
@ -498,12 +499,12 @@ void sfz::Voice::filterStageMono(AudioSpan<float> buffer) noexcept
|
|||
const auto leftBuffer = buffer.getSpan(0);
|
||||
const float* inputChannel[1] { leftBuffer.data() };
|
||||
float* outputChannel[1] { leftBuffer.data() };
|
||||
for (auto& filter : filters) {
|
||||
filter->process(inputChannel, outputChannel, numSamples);
|
||||
for (unsigned i = 0; i < region->filters.size(); ++i) {
|
||||
filters[i].process(inputChannel, outputChannel, numSamples);
|
||||
}
|
||||
|
||||
for (auto& eq : equalizers) {
|
||||
eq->process(inputChannel, outputChannel, numSamples);
|
||||
for (unsigned i = 0; i < region->equalizers.size(); ++i) {
|
||||
equalizers[i].process(inputChannel, outputChannel, numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -517,12 +518,12 @@ void sfz::Voice::filterStageStereo(AudioSpan<float> buffer) noexcept
|
|||
const float* inputChannels[2] { leftBuffer.data(), rightBuffer.data() };
|
||||
float* outputChannels[2] { leftBuffer.data(), rightBuffer.data() };
|
||||
|
||||
for (auto& filter : filters) {
|
||||
filter->process(inputChannels, outputChannels, numSamples);
|
||||
for (unsigned i = 0; i < region->filters.size(); ++i) {
|
||||
filters[i].process(inputChannels, outputChannels, numSamples);
|
||||
}
|
||||
|
||||
for (auto& eq : equalizers) {
|
||||
eq->process(inputChannels, outputChannels, numSamples);
|
||||
for (unsigned i = 0; i < region->equalizers.size(); ++i) {
|
||||
equalizers[i].process(inputChannels, outputChannels, numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -611,7 +612,7 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
sourcePosition = indices->back();
|
||||
floatPositionOffset = coeffs->back();
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(0)));
|
||||
ASSERT(!hasNanInf(buffer.getConstSpan(1)));
|
||||
SFIZZ_CHECK(isReasonableAudio(buffer.getConstSpan(0)));
|
||||
|
|
@ -731,8 +732,11 @@ void sfz::Voice::reset() noexcept
|
|||
|
||||
powerFollower.clear();
|
||||
|
||||
filters.clear();
|
||||
equalizers.clear();
|
||||
for (auto& filter : filters)
|
||||
filter.reset();
|
||||
|
||||
for (auto& eq : equalizers)
|
||||
eq.reset();
|
||||
|
||||
removeVoiceFromRing();
|
||||
}
|
||||
|
|
@ -776,16 +780,22 @@ uint32_t sfz::Voice::getSourcePosition() const noexcept
|
|||
|
||||
void sfz::Voice::setMaxFiltersPerVoice(size_t numFilters)
|
||||
{
|
||||
// There are filters in there, this call is unexpected
|
||||
ASSERT(filters.size() == 0);
|
||||
filters.reserve(numFilters);
|
||||
if (numFilters == filters.size())
|
||||
return;
|
||||
|
||||
filters.clear();
|
||||
for (unsigned i = 0; i < numFilters; ++i)
|
||||
filters.emplace_back(resources);
|
||||
}
|
||||
|
||||
void sfz::Voice::setMaxEQsPerVoice(size_t numFilters)
|
||||
{
|
||||
// There are filters in there, this call is unexpected
|
||||
ASSERT(equalizers.size() == 0);
|
||||
equalizers.reserve(numFilters);
|
||||
if (numFilters == equalizers.size())
|
||||
return;
|
||||
|
||||
equalizers.clear();
|
||||
for (unsigned i = 0; i < numFilters; ++i)
|
||||
equalizers.emplace_back(resources);
|
||||
}
|
||||
|
||||
void sfz::Voice::setMaxLFOsPerVoice(size_t numLFOs)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "Region.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "Resources.h"
|
||||
#include "FilterPool.h"
|
||||
#include "EQPool.h"
|
||||
#include "Smoothers.h"
|
||||
#include "AudioSpan.h"
|
||||
#include "LeakDetector.h"
|
||||
|
|
@ -454,8 +456,8 @@ private:
|
|||
|
||||
Resources& resources;
|
||||
|
||||
std::vector<FilterHolderPtr> filters;
|
||||
std::vector<EQHolderPtr> equalizers;
|
||||
std::vector<FilterHolder> filters;
|
||||
std::vector<EQHolder> equalizers;
|
||||
std::vector<std::unique_ptr<LFO>> lfos;
|
||||
std::vector<std::unique_ptr<FlexEnvelope>> flexEGs;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue