From dc4f59107bac4bed0ea5218b94cf6f01a0c91323 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 16 Sep 2020 13:42:20 +0200 Subject: [PATCH] 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 --- src/sfizz/EQPool.cpp | 107 +++++++++------------------------------ src/sfizz/EQPool.h | 86 ++++--------------------------- src/sfizz/FilterPool.cpp | 107 +++++++++------------------------------ src/sfizz/FilterPool.h | 87 ++++--------------------------- src/sfizz/Resources.h | 7 +-- src/sfizz/Voice.cpp | 72 ++++++++++++++------------ src/sfizz/Voice.h | 6 ++- 7 files changed, 111 insertions(+), 361 deletions(-) diff --git a/src/sfizz/EQPool.cpp b/src/sfizz/EQPool.cpp index cc608a12..7e42546b 100644 --- a/src/sfizz/EQPool.cpp +++ b/src/sfizz/EQPool.cpp @@ -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(); + 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({ 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(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 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 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(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(sampleRate)); } diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index d1f7cebb..5b61c096 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -1,7 +1,7 @@ #pragma once #include "SfzFilter.h" #include "EQDescription.h" -#include "MidiState.h" +#include "Resources.h" #include "utility/SpinMutex.h" #include #include @@ -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 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; - -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 eqs; -}; } diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index 70811320..de271a06 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -5,15 +5,16 @@ #include #include -sfz::FilterHolder::FilterHolder(const MidiState& midiState) -: midiState(midiState) +sfz::FilterHolder::FilterHolder(const Resources& resources) +: resources(resources) { - + filter = absl::make_unique(); + 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({ 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 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 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(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(sampleRate)); + filter->init(static_cast(sampleRate)); } diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index 197eb8ad..c926f196 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -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 @@ -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; 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; filterRandomDist dist { 0, sfz::Default::filterRandom }; }; -using FilterHolderPtr = std::shared_ptr; - -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(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 filters; -}; } diff --git a/src/sfizz/Resources.h b/src/sfizz/Resources.h index 645482cd..577ff756 100644 --- a/src/sfizz/Resources.h +++ b/src/sfizz/Resources.h @@ -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 stretch; @@ -39,8 +36,6 @@ struct Resources void setSampleRate(float samplerate) { midiState.setSampleRate(samplerate); - filterPool.setSampleRate(samplerate); - eqPool.setSampleRate(samplerate); modMatrix.setSampleRate(samplerate); } diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index cb604633..6cc473d0 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -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 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 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 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) diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 8833271a..8afe3a06 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -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 filters; - std::vector equalizers; + std::vector filters; + std::vector equalizers; std::vector> lfos; std::vector> flexEGs;