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 "SIMDHelpers.h"
#include "absl/algorithm/container.h"
#include "AtomicGuard.h"
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
sfz::FilterHolder::FilterHolder(const 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!
// For now we take the last value
auto cutoff = baseCutoff;
lastCutoff = baseCutoff;
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) {
resonance += midiState.getCCValue(mod.first) * mod.second;
lastResonance += midiState.getCCValue(mod.first) * mod.second;
}
auto gain = baseGain;
lastGain = baseGain;
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)
: 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)
{
AtomicGuard guard { givingOutFilters };
if (!canGiveOutFilters)
return {};
auto filter = absl::c_find_if(filters, [](const FilterHolderPtr& holder) {
return holder.use_count() == 1;
});
@ -81,17 +101,34 @@ sfz::FilterHolderPtr sfz::FilterPool::getFilter(const FilterDescription& descrip
return *filter;
}
int sfz::FilterPool::getActiveFilters() const
size_t sfz::FilterPool::getActiveFilters() const
{
return absl::c_count_if(filters, [](const FilterHolderPtr& holder) {
return holder.use_count() > 1;
});
}
void sfz::FilterPool::setNumFilters(int numFilters)
size_t sfz::FilterPool::setNumFilters(size_t numFilters)
{
filters.clear();
filters.reserve(numFilters);
for (int i = 0; i < numFilters; ++i)
AtomicDisabler disabler { canGiveOutFilters };
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));
return filters.size();
}

View file

@ -13,16 +13,54 @@ class FilterHolder
public:
FilterHolder() = delete;
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);
/**
* @brief Process a block of stereo inputs
*
* @param inputs
* @param outputs
* @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;
private:
/**
* Reset the filter. Is called internally when using setup().
*/
void reset();
const MidiState& midiState;
const FilterDescription* description;
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 };
using filterRandomDist = std::uniform_int_distribution<int>;
filterRandomDist dist { 0, sfz::Default::filterRandom };
};
@ -33,11 +71,42 @@ 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::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);
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:
std::atomic<bool> givingOutFilters { false };
std::atomic<bool> canGiveOutFilters { true };
const MidiState& midiState;
std::vector<FilterHolderPtr> filters;
};