Added comments and working on the filter pool
This commit is contained in:
parent
290860502f
commit
43ace5defb
2 changed files with 121 additions and 15 deletions
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue