sfizz/src/sfizz/FilterPool.cpp
2020-03-08 17:03:09 +01:00

147 lines
4.6 KiB
C++

#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)
{
}
void sfz::FilterHolder::reset()
{
filter.clear();
}
void sfz::FilterHolder::setup(const FilterDescription& description, unsigned numChannels, int noteNumber, uint8_t velocity)
{
this->description = &description;
filter.setType(description.type);
filter.setChannels(numChannels);
// Setup the base values
baseCutoff = description.cutoff;
if (description.random != 0) {
dist.param(filterRandomDist::param_type(0, description.random));
baseCutoff *= centsFactor(dist(Random::randomGenerator));
}
const auto keytrack = description.keytrack * (noteNumber - description.keycenter);
baseCutoff *= centsFactor(keytrack);
const auto veltrack = static_cast<float>(description.veltrack) * normalizeVelocity(velocity);
baseCutoff *= centsFactor(veltrack);
baseCutoff = Default::filterCutoffRange.clamp(baseCutoff);
baseGain = description.gain;
baseResonance = description.resonance;
// Setup the modulated values
lastCutoff = midiState.modulate<float, int>(baseCutoff, description.cutoffCC, Default::filterCutoffRange, multiplyByCents);
lastResonance = midiState.modulate(baseResonance, description.resonanceCC, Default::filterResonanceRange);
baseGain = midiState.modulate(baseGain, description.gainCC, Default::filterGainRange);
// Initialize the filter
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++)
copy<float>({ inputs[channelIdx], numFrames }, { outputs[channelIdx], numFrames });
return;
}
// 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 = midiState.modulate<float, int>(baseCutoff, description->cutoffCC, Default::filterCutoffRange, multiplyByCents);
lastResonance = midiState.modulate(baseResonance, description->resonanceCC, Default::filterResonanceRange);
baseGain = midiState.modulate(baseGain, description->gainCC, Default::filterGainRange);
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, uint8_t velocity)
{
AtomicGuard guard { givingOutFilters };
if (!canGiveOutFilters)
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)
{
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));
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<double>(sampleRate));
}