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 "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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue