Added comments and working on the filter pool

This commit is contained in:
Paul Fd 2020-02-09 13:29:42 +01:00
parent 290860502f
commit 43ace5defb
2 changed files with 121 additions and 15 deletions

View file

@ -1,6 +1,10 @@
#include "FilterPool.h" #include "FilterPool.h"
#include "SIMDHelpers.h" #include "SIMDHelpers.h"
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "AtomicGuard.h"
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
sfz::FilterHolder::FilterHolder(const MidiState& midiState) sfz::FilterHolder::FilterHolder(const MidiState& midiState)
: midiState(midiState) : midiState(midiState)
@ -43,24 +47,36 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned
// TODO: Once the midistate envelopes are done, add modulation in there! // TODO: Once the midistate envelopes are done, add modulation in there!
// For now we take the last value // For now we take the last value
auto cutoff = baseCutoff; lastCutoff = baseCutoff;
for (auto& mod: description->cutoffCC) { for (auto& mod: description->cutoffCC) {
cutoff *= centsFactor(midiState.getCCValue(mod.first) * mod.second); lastCutoff *= centsFactor(midiState.getCCValue(mod.first) * mod.second);
} }
auto resonance = baseResonance; lastResonance = baseResonance;
for (auto& mod: description->resonanceCC) { for (auto& mod: description->resonanceCC) {
resonance += midiState.getCCValue(mod.first) * mod.second; lastResonance += midiState.getCCValue(mod.first) * mod.second;
} }
auto gain = baseGain; lastGain = baseGain;
for (auto& mod: description->gainCC) { for (auto& mod: description->gainCC) {
gain += midiState.getCCValue(mod.first) * mod.second; lastResonance += midiState.getCCValue(mod.first) * mod.second;
} }
filter.process(inputs, outputs, cutoff, resonance, gain,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) sfz::FilterPool::FilterPool(const MidiState& state, int numFilters)
: midiState(state) : midiState(state)
@ -70,6 +86,10 @@ sfz::FilterPool::FilterPool(const MidiState& state, int numFilters)
sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& description, int noteNumber, uint8_t velocity) sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& description, int noteNumber, uint8_t velocity)
{ {
AtomicGuard guard { givingOutFilters };
if (!canGiveOutFilters)
return {};
auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) { auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) {
return holder.use_count() == 1; return holder.use_count() == 1;
}); });
@ -81,17 +101,34 @@ sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& descrip
return *filter; return *filter;
} }
int sfz::FilterPool::getActiveFilters() const size_t sfz::FilterPool::getActiveFilters() const
{ {
return absl::c_count_if(filters, [](const FilterHolderPtr& holder) { return absl::c_count_if(filters, [](const FilterHolderPtr& holder) {
return holder.use_count() > 1; return holder.use_count() > 1;
}); });
} }
void sfz::FilterPool::setNumFilters(int numFilters) size_t sfz::FilterPool::setNumFilters(size_t numFilters)
{ {
filters.clear(); AtomicDisabler disabler { canGiveOutFilters };
filters.reserve(numFilters);
for (int i = 0; i < numFilters; ++i) while(givingOutFilters)
std::this_thread::sleep_for(1ms);
auto filterIterator = filters.begin();
auto filterSentinel = filters.rbegin();
while (filterIterator < filterSentinel.base()) {
if (filterIterator->use_count() == 1) {
std::iter_swap(filterIterator, filterSentinel);
++filterSentinel;
} else {
++filterIterator;
}
}
filters.resize(std::distance(filters.begin(), filterSentinel.base()));
for (size_t i = filters.size(); i < numFilters; ++i)
filters.emplace_back(std::make_shared<FilterHolder>(midiState)); filters.emplace_back(std::make_shared<FilterHolder>(midiState));
return filters.size();
} }

View file

@ -13,16 +13,54 @@ class FilterHolder
public: public:
FilterHolder() = delete; FilterHolder() = delete;
FilterHolder(const MidiState& state); FilterHolder(const MidiState& state);
void reset(); /**
* @brief Setup a new filter based on a filter description, and a triggering note parameters.
*
* @param description the filter description
* @param noteNumber the triggering note number
* @param velocity the triggering note velocity
*/
void setup(const FilterDescription& description, int noteNumber = static_cast<int>(Default::filterKeycenter), uint8_t velocity = 0); void setup(const FilterDescription& description, int noteNumber = static_cast<int>(Default::filterKeycenter), uint8_t velocity = 0);
/**
* @brief Process a block of stereo inputs
*
* @param inputs
* @param outputs
* @param numFrames
*/
void process(const float** inputs, float** outputs, unsigned 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;
private: private:
/**
* Reset the filter. Is called internally when using setup().
*/
void reset();
const MidiState& midiState; const MidiState& midiState;
const FilterDescription* description; const FilterDescription* description;
Filter filter; 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 };
float lastCutoff { Default::filterCutoff };
float lastResonance { Default::filterResonance };
float lastGain { Default::filterGain };
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 };
}; };
@ -33,11 +71,42 @@ class FilterPool
{ {
public: public:
FilterPool() = delete; 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::defaultNumFilters); FilterPool(const MidiState& state, int numFilters = config::defaultNumFilters);
/**
* @brief Get a filter object to use in Voices
*
* @param description the filter description to bind to the 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, int noteNumber = static_cast<int>(Default::filterKeycenter), uint8_t velocity = 0); FilterHolderPtr getFilter(const FilterDescription& description, int noteNumber = static_cast<int>(Default::filterKeycenter), uint8_t velocity = 0);
int getActiveFilters() const; /**
void setNumFilters(int numFilters); * @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);
private: private:
std::atomic<bool> givingOutFilters { false };
std::atomic<bool> canGiveOutFilters { true };
const MidiState& midiState; const MidiState& midiState;
std::vector<FilterHolderPtr> filters; std::vector<FilterHolderPtr> filters;
}; };