From 9999ca65d3de993cd7323241ba9fdc73d4e7df54 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 7 Feb 2020 02:20:32 +0100 Subject: [PATCH] Revised interface for filter --- scripts/generate_filters.sh | 4 +- src/sfizz/SfzFilter.cpp | 442 ++++++++++++++++++----------------- src/sfizz/SfzFilter.h | 34 ++- src/sfizz/SfzFilterImpls.cxx | 163 ++++++------- 4 files changed, 335 insertions(+), 308 deletions(-) diff --git a/scripts/generate_filters.sh b/scripts/generate_filters.sh index e519ea32..6d2c65a2 100755 --- a/scripts/generate_filters.sh +++ b/scripts/generate_filters.sh @@ -15,7 +15,7 @@ faustgen() { mkdir -p src/sfizz/gen/filters local outfile=src/sfizz/gen/filters/sfz"$1".cxx - local code=`faust $FAUSTARGS -pn sfz"$1" -cn faust"$1" src/sfizz/dsp/filters/sfz_filters.dsp` + local code=`faust $FAUSTARGS -pn sfz"$1" -cn faust"$1" -scn sfzFilterDsp src/sfizz/dsp/filters/sfz_filters.dsp` # find variable names of our controls local cutoffVar=`echo "$code" | $SED -r 's%.*\("Cutoff", &[ \t]*([a-zA-Z0-9_]+).*%\1%;t;d'` @@ -35,8 +35,6 @@ faustgen() { # direct access to parameter variables $SED -r -i 's/\bprivate:/public:/' "$outfile" - # no virtuals please - $SED -r -i 's/\bvirtual\b//' "$outfile" # rename the variables for us to access more easily if test ! -z "$cutoffVar"; then diff --git a/src/sfizz/SfzFilter.cpp b/src/sfizz/SfzFilter.cpp index 8c023dfc..31ba1d90 100644 --- a/src/sfizz/SfzFilter.cpp +++ b/src/sfizz/SfzFilter.cpp @@ -16,229 +16,167 @@ namespace sfz { //------------------------------------------------------------------------------ // SFZ v2 multi-mode filter -template -struct Filter::Impl { +struct Filter::Impl { FilterType fType = kFilterNone; + unsigned fChannels = 1; + enum { maxChannels = 2 }; - sfzLpf1p fDspLpf1p; - sfzLpf2p fDspLpf2p; - sfzLpf4p fDspLpf4p; - sfzLpf6p fDspLpf6p; - sfzHpf1p fDspHpf1p; - sfzHpf2p fDspHpf2p; - sfzHpf4p fDspHpf4p; - sfzHpf6p fDspHpf6p; - sfzBpf1p fDspBpf1p; - sfzBpf2p fDspBpf2p; - sfzBpf4p fDspBpf4p; - sfzBpf6p fDspBpf6p; - sfzApf1p fDspApf1p; - sfzBrf1p fDspBrf1p; - sfzBrf2p fDspBrf2p; - sfzPink fDspPink; - sfzLpf2pSv fDspLpf2pSv; - sfzHpf2pSv fDspHpf2pSv; - sfzBpf2pSv fDspBpf2pSv; - sfzBrf2pSv fDspBrf2pSv; - sfzLsh fDspLsh; - sfzHsh fDspHsh; - sfzPeq fDspPeq; + sfzLpf1p fDspLpf1p; + sfzLpf2p fDspLpf2p; + sfzLpf4p fDspLpf4p; + sfzLpf6p fDspLpf6p; + sfzHpf1p fDspHpf1p; + sfzHpf2p fDspHpf2p; + sfzHpf4p fDspHpf4p; + sfzHpf6p fDspHpf6p; + sfzBpf1p fDspBpf1p; + sfzBpf2p fDspBpf2p; + sfzBpf4p fDspBpf4p; + sfzBpf6p fDspBpf6p; + sfzApf1p fDspApf1p; + sfzBrf1p fDspBrf1p; + sfzBrf2p fDspBrf2p; + sfzPink fDspPink; + sfzLpf2pSv fDspLpf2pSv; + sfzHpf2pSv fDspHpf2pSv; + sfzBpf2pSv fDspBpf2pSv; + sfzBrf2pSv fDspBrf2pSv; + sfzLsh fDspLsh; + sfzHsh fDspHsh; + sfzPeq fDspPeq; - template static void process(F &filter, const float *const in[NCh], float *const out[NCh], float cutoff, float q, float pksh, unsigned nframes); - template static void processModulated(F &filter, const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *q, const float *pksh, unsigned nframes); + sfz2chLpf1p fDsp2chLpf1p; + sfz2chLpf2p fDsp2chLpf2p; + sfz2chLpf4p fDsp2chLpf4p; + sfz2chLpf6p fDsp2chLpf6p; + sfz2chHpf1p fDsp2chHpf1p; + sfz2chHpf2p fDsp2chHpf2p; + sfz2chHpf4p fDsp2chHpf4p; + sfz2chHpf6p fDsp2chHpf6p; + sfz2chBpf1p fDsp2chBpf1p; + sfz2chBpf2p fDsp2chBpf2p; + sfz2chBpf4p fDsp2chBpf4p; + sfz2chBpf6p fDsp2chBpf6p; + sfz2chApf1p fDsp2chApf1p; + sfz2chBrf1p fDsp2chBrf1p; + sfz2chBrf2p fDsp2chBrf2p; + sfz2chPink fDsp2chPink; + sfz2chLpf2pSv fDsp2chLpf2pSv; + sfz2chHpf2pSv fDsp2chHpf2pSv; + sfz2chBpf2pSv fDsp2chBpf2pSv; + sfz2chBrf2pSv fDsp2chBrf2pSv; + sfz2chLsh fDsp2chLsh; + sfz2chHsh fDsp2chHsh; + sfz2chPeq fDsp2chPeq; + + sfzFilterDsp *getDsp(unsigned channels, FilterType type); + + static constexpr uint32_t idDsp(unsigned channels, FilterType type) + { + return static_cast(type)|(channels << 16); + } }; -template -Filter::Filter() +Filter::Filter() : P{new Impl} { } -template -Filter::~Filter() +Filter::~Filter() { } -template -void Filter::init(double sampleRate) +void Filter::init(double sampleRate) { - P->fDspLpf1p.init(sampleRate); - P->fDspLpf2p.init(sampleRate); - P->fDspLpf4p.init(sampleRate); - P->fDspLpf6p.init(sampleRate); - P->fDspHpf1p.init(sampleRate); - P->fDspHpf2p.init(sampleRate); - P->fDspHpf4p.init(sampleRate); - P->fDspHpf6p.init(sampleRate); - P->fDspBpf1p.init(sampleRate); - P->fDspBpf2p.init(sampleRate); - P->fDspBpf4p.init(sampleRate); - P->fDspBpf6p.init(sampleRate); - P->fDspApf1p.init(sampleRate); - P->fDspBrf1p.init(sampleRate); - P->fDspBrf2p.init(sampleRate); - P->fDspPink.init(sampleRate); - P->fDspLpf2pSv.init(sampleRate); - P->fDspHpf2pSv.init(sampleRate); - P->fDspBpf2pSv.init(sampleRate); - P->fDspBrf2pSv.init(sampleRate); - P->fDspLsh.init(sampleRate); - P->fDspHsh.init(sampleRate); - P->fDspPeq.init(sampleRate); -} - -template -void Filter::clear() -{ - switch (P->fType) { - case kFilterNone: break; - case kFilterApf1p: P->fDspApf1p.instanceClear(); break; - case kFilterBpf1p: P->fDspBpf1p.instanceClear(); break; - case kFilterBpf2p: P->fDspBpf2p.instanceClear(); break; - case kFilterBpf4p: P->fDspBpf4p.instanceClear(); break; - case kFilterBpf6p: P->fDspBpf6p.instanceClear(); break; - case kFilterBrf1p: P->fDspBrf1p.instanceClear(); break; - case kFilterBrf2p: P->fDspBrf2p.instanceClear(); break; - case kFilterHpf1p: P->fDspHpf1p.instanceClear(); break; - case kFilterHpf2p: P->fDspHpf2p.instanceClear(); break; - case kFilterHpf4p: P->fDspHpf4p.instanceClear(); break; - case kFilterHpf6p: P->fDspHpf6p.instanceClear(); break; - case kFilterLpf1p: P->fDspLpf1p.instanceClear(); break; - case kFilterLpf2p: P->fDspLpf2p.instanceClear(); break; - case kFilterLpf4p: P->fDspLpf4p.instanceClear(); break; - case kFilterLpf6p: P->fDspLpf6p.instanceClear(); break; - case kFilterPink: P->fDspPink.instanceClear(); break; - case kFilterLpf2pSv: P->fDspLpf2pSv.instanceClear(); break; - case kFilterHpf2pSv: P->fDspHpf2pSv.instanceClear(); break; - case kFilterBpf2pSv: P->fDspBpf2pSv.instanceClear(); break; - case kFilterBrf2pSv: P->fDspBrf2pSv.instanceClear(); break; - case kFilterLsh: P->fDspLsh.instanceClear(); break; - case kFilterHsh: P->fDspHsh.instanceClear(); break; - case kFilterPeq: P->fDspPeq.instanceClear(); break; + for (unsigned channels = 1; channels <= Impl::maxChannels; ++channels) { + FilterType ftype = static_cast(1); + while (sfzFilterDsp *dsp = P->getDsp(channels, ftype)) { + dsp->init(sampleRate); + ftype = static_cast(static_cast(ftype) + 1); + } } } -template -template -void Filter::Impl::process(F &filter, const float *const in[NCh], float *const out[NCh], float cutoff, float q, float pksh, unsigned nframes) +void Filter::clear() { - filter.setCutoff(cutoff); - filter.setQ(q); - filter.setPkShGain(pksh); - filter.compute(nframes, const_cast(in), const_cast(out)); + sfzFilterDsp *dsp = P->getDsp(P->fChannels, P->fType); + + if (dsp) + dsp->instanceClear(); } -template -void Filter::process(const float *const in[NCh], float *const out[NCh], float cutoff, float q, float pksh, unsigned nframes) +void Filter::process(const float *const in[], float *const out[], float cutoff, float q, float pksh, unsigned nframes) { - if (P->fType == kFilterNone) { - for (unsigned c = 0; c < NCh; ++c) + unsigned channels = P->fChannels; + sfzFilterDsp *dsp = P->getDsp(channels, P->fType); + + if (!dsp) { + for (unsigned c = 0; c < channels; ++c) copy({ in[c], nframes }, { out[c], nframes }); return; } - switch (P->fType) { - case kFilterApf1p: P->process(P->fDspApf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf1p: P->process(P->fDspBpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf2p: P->process(P->fDspBpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf4p: P->process(P->fDspBpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf6p: P->process(P->fDspBpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf1p: P->process(P->fDspBrf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf2p: P->process(P->fDspBrf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf1p: P->process(P->fDspHpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf2p: P->process(P->fDspHpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf4p: P->process(P->fDspHpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf6p: P->process(P->fDspHpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf1p: P->process(P->fDspLpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf2p: P->process(P->fDspLpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf4p: P->process(P->fDspLpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf6p: P->process(P->fDspLpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterPink: P->process(P->fDspPink, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf2pSv: P->process(P->fDspLpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf2pSv: P->process(P->fDspHpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf2pSv: P->process(P->fDspBpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf2pSv: P->process(P->fDspBrf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterLsh: P->process(P->fDspLsh, in, out, cutoff, q, pksh, nframes); break; - case kFilterHsh: P->process(P->fDspHsh, in, out, cutoff, q, pksh, nframes); break; - case kFilterPeq: P->process(P->fDspPeq, in, out, cutoff, q, pksh, nframes); break; - default: assert(false); - } + dsp->setCutoff(cutoff); + dsp->setQ(q); + dsp->setPkShGain(pksh); + dsp->compute(nframes, const_cast(in), const_cast(out)); } -template -template -void Filter::Impl::processModulated(F &filter, const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *q, const float *pksh, unsigned nframes) +void Filter::processModulated(const float *const in[], float *const out[], const float *cutoff, const float *q, const float *pksh, unsigned nframes) { - unsigned frame = 0; + unsigned channels = P->fChannels; + sfzFilterDsp *dsp = P->getDsp(channels, P->fType); + if (!dsp) { + for (unsigned c = 0; c < channels; ++c) + copy({ in[c], nframes }, { out[c], nframes }); + return; + } + + unsigned frame = 0; while (frame < nframes) { unsigned current = nframes - frame; if (current > config::filterControlInterval) current = config::filterControlInterval; - const float *current_in[NCh]; - float *current_out[NCh]; + const float *current_in[Impl::maxChannels]; + float *current_out[Impl::maxChannels]; - for (unsigned c = 0; c < NCh; ++c) { + for (unsigned c = 0; c < channels; ++c) { current_in[c] = in[c] + frame; current_out[c] = out[c] + frame; } - filter.setCutoff(cutoff[frame]); - filter.setQ(q[frame]); - filter.setPkShGain(pksh[frame]); - filter.compute(current, const_cast(current_in), const_cast(current_out)); + dsp->setCutoff(cutoff[frame]); + dsp->setQ(q[frame]); + dsp->setPkShGain(pksh[frame]); + dsp->compute(current, const_cast(current_in), const_cast(current_out)); frame += current; } } -template -void Filter::processModulated(const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *q, const float *pksh, unsigned nframes) +unsigned Filter::channels() const { - if (P->fType == kFilterNone) { - for (unsigned c = 0; c < NCh; ++c) - copy({ in[c], nframes }, { out[c], nframes }); - return; - } + return P->fChannels; +} - switch (P->fType) { - case kFilterApf1p: P->processModulated(P->fDspApf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf1p: P->processModulated(P->fDspBpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf2p: P->processModulated(P->fDspBpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf4p: P->processModulated(P->fDspBpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf6p: P->processModulated(P->fDspBpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf1p: P->processModulated(P->fDspBrf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf2p: P->processModulated(P->fDspBrf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf1p: P->processModulated(P->fDspHpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf2p: P->processModulated(P->fDspHpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf4p: P->processModulated(P->fDspHpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf6p: P->processModulated(P->fDspHpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf1p: P->processModulated(P->fDspLpf1p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf2p: P->processModulated(P->fDspLpf2p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf4p: P->processModulated(P->fDspLpf4p, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf6p: P->processModulated(P->fDspLpf6p, in, out, cutoff, q, pksh, nframes); break; - case kFilterPink: P->processModulated(P->fDspPink, in, out, cutoff, q, pksh, nframes); break; - case kFilterLpf2pSv: P->processModulated(P->fDspLpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterHpf2pSv: P->processModulated(P->fDspHpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterBpf2pSv: P->processModulated(P->fDspBpf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterBrf2pSv: P->processModulated(P->fDspBrf2pSv, in, out, cutoff, q, pksh, nframes); break; - case kFilterLsh: P->processModulated(P->fDspLsh, in, out, cutoff, q, pksh, nframes); break; - case kFilterHsh: P->processModulated(P->fDspHsh, in, out, cutoff, q, pksh, nframes); break; - case kFilterPeq: P->processModulated(P->fDspPeq, in, out, cutoff, q, pksh, nframes); break; - default: assert(false); +void Filter::setChannels(unsigned channels) +{ + assert(channels < Impl::maxChannels); + if (P->fChannels != channels) { + P->fChannels = channels; + clear(); } } -template -FilterType Filter::type() const +FilterType Filter::type() const { return P->fType; } -template -void Filter::setType(FilterType type) +void Filter::setType(FilterType type) { if (P->fType != type) { P->fType = type; @@ -246,87 +184,175 @@ void Filter::setType(FilterType type) } } -template class Filter<1>; -template class Filter<2>; +sfzFilterDsp *Filter::Impl::getDsp(unsigned channels, FilterType type) +{ + switch (idDsp(channels, type)) { + default: return nullptr; + + case idDsp(1, kFilterApf1p): return &fDspApf1p; + case idDsp(1, kFilterBpf1p): return &fDspBpf1p; + case idDsp(1, kFilterBpf2p): return &fDspBpf2p; + case idDsp(1, kFilterBpf4p): return &fDspBpf4p; + case idDsp(1, kFilterBpf6p): return &fDspBpf6p; + case idDsp(1, kFilterBrf1p): return &fDspBrf1p; + case idDsp(1, kFilterBrf2p): return &fDspBrf2p; + case idDsp(1, kFilterHpf1p): return &fDspHpf1p; + case idDsp(1, kFilterHpf2p): return &fDspHpf2p; + case idDsp(1, kFilterHpf4p): return &fDspHpf4p; + case idDsp(1, kFilterHpf6p): return &fDspHpf6p; + case idDsp(1, kFilterLpf1p): return &fDspLpf1p; + case idDsp(1, kFilterLpf2p): return &fDspLpf2p; + case idDsp(1, kFilterLpf4p): return &fDspLpf4p; + case idDsp(1, kFilterLpf6p): return &fDspLpf6p; + case idDsp(1, kFilterPink): return &fDspPink; + case idDsp(1, kFilterLpf2pSv): return &fDspLpf2pSv; + case idDsp(1, kFilterHpf2pSv): return &fDspHpf2pSv; + case idDsp(1, kFilterBpf2pSv): return &fDspBpf2pSv; + case idDsp(1, kFilterBrf2pSv): return &fDspBrf2pSv; + case idDsp(1, kFilterLsh): return &fDspLsh; + case idDsp(1, kFilterHsh): return &fDspHsh; + case idDsp(1, kFilterPeq): return &fDspPeq; + + case idDsp(2, kFilterApf1p): return &fDsp2chApf1p; + case idDsp(2, kFilterBpf1p): return &fDsp2chBpf1p; + case idDsp(2, kFilterBpf2p): return &fDsp2chBpf2p; + case idDsp(2, kFilterBpf4p): return &fDsp2chBpf4p; + case idDsp(2, kFilterBpf6p): return &fDsp2chBpf6p; + case idDsp(2, kFilterBrf1p): return &fDsp2chBrf1p; + case idDsp(2, kFilterBrf2p): return &fDsp2chBrf2p; + case idDsp(2, kFilterHpf1p): return &fDsp2chHpf1p; + case idDsp(2, kFilterHpf2p): return &fDsp2chHpf2p; + case idDsp(2, kFilterHpf4p): return &fDsp2chHpf4p; + case idDsp(2, kFilterHpf6p): return &fDsp2chHpf6p; + case idDsp(2, kFilterLpf1p): return &fDsp2chLpf1p; + case idDsp(2, kFilterLpf2p): return &fDsp2chLpf2p; + case idDsp(2, kFilterLpf4p): return &fDsp2chLpf4p; + case idDsp(2, kFilterLpf6p): return &fDsp2chLpf6p; + case idDsp(2, kFilterPink): return &fDsp2chPink; + case idDsp(2, kFilterLpf2pSv): return &fDsp2chLpf2pSv; + case idDsp(2, kFilterHpf2pSv): return &fDsp2chHpf2pSv; + case idDsp(2, kFilterBpf2pSv): return &fDsp2chBpf2pSv; + case idDsp(2, kFilterBrf2pSv): return &fDsp2chBrf2pSv; + case idDsp(2, kFilterLsh): return &fDsp2chLsh; + case idDsp(2, kFilterHsh): return &fDsp2chHsh; + case idDsp(2, kFilterPeq): return &fDsp2chPeq; + } +} //------------------------------------------------------------------------------ // SFZ v1 equalizer filter -template -struct FilterEq::Impl { - sfzEq fDsp; +struct FilterEq::Impl { + unsigned fChannels = 1; + enum { maxChannels = 2 }; + + sfzEq fDsp; + sfz2chEq fDsp2ch; + + sfzFilterDsp *getDsp(unsigned channels); }; -template -FilterEq::FilterEq() +FilterEq::FilterEq() : P{new Impl} { } -template -FilterEq::~FilterEq() +FilterEq::~FilterEq() { } -template -void FilterEq::init(double sampleRate) +void FilterEq::init(double sampleRate) { - sfzEq &filter = P->fDsp; - - filter.init(sampleRate); + for (unsigned channels = 1; channels <= Impl::maxChannels; ++channels) { + sfzFilterDsp *dsp = P->getDsp(channels); + dsp->init(sampleRate); + } } -template -void FilterEq::clear() +void FilterEq::clear() { - sfzEq &filter = P->fDsp; + sfzFilterDsp *dsp = P->getDsp(P->fChannels); - filter.instanceClear(); + if (dsp) + dsp->instanceClear(); } -template -void FilterEq::process(const float *const in[NCh], float *const out[NCh], float cutoff, float bw, float pksh, unsigned nframes) +void FilterEq::process(const float *const in[], float *const out[], float cutoff, float bw, float pksh, unsigned nframes) { - sfzEq &filter = P->fDsp; + unsigned channels = P->fChannels; + sfzFilterDsp *dsp = P->getDsp(channels); - filter.setCutoff(cutoff); - filter.setBandwidth(bw); - filter.setPkShGain(pksh); - filter.compute(nframes, const_cast(in), const_cast(out)); + if (!dsp) { + for (unsigned c = 0; c < channels; ++c) + copy({ in[c], nframes }, { out[c], nframes }); + return; + } + + dsp->setCutoff(cutoff); + dsp->setBandwidth(bw); + dsp->setPkShGain(pksh); + dsp->compute(nframes, const_cast(in), const_cast(out)); } -template -void FilterEq::processModulated(const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *bw, const float *pksh, unsigned nframes) +void FilterEq::processModulated(const float *const in[], float *const out[], const float *cutoff, const float *bw, const float *pksh, unsigned nframes) { - sfzEq &filter = P->fDsp; + unsigned channels = P->fChannels; + sfzFilterDsp *dsp = P->getDsp(channels); + + if (!dsp) { + for (unsigned c = 0; c < channels; ++c) + copy({ in[c], nframes }, { out[c], nframes }); + return; + } unsigned frame = 0; - while (frame < nframes) { unsigned current = nframes - frame; if (current > config::filterControlInterval) current = config::filterControlInterval; - const float *current_in[NCh]; - float *current_out[NCh]; + const float *current_in[Impl::maxChannels]; + float *current_out[Impl::maxChannels]; - for (unsigned c = 0; c < NCh; ++c) { + for (unsigned c = 0; c < channels; ++c) { current_in[c] = in[c] + frame; current_out[c] = out[c] + frame; } - filter.setCutoff(cutoff[frame]); - filter.setBandwidth(bw[frame]); - filter.setPkShGain(pksh[frame]); - filter.compute(current, const_cast(current_in), const_cast(current_out)); + dsp->setCutoff(cutoff[frame]); + dsp->setBandwidth(bw[frame]); + dsp->setPkShGain(pksh[frame]); + dsp->compute(current, const_cast(current_in), const_cast(current_out)); frame += current; } } -template class FilterEq<1>; -template class FilterEq<2>; + +unsigned FilterEq::channels() const +{ + return P->fChannels; +} + +void FilterEq::setChannels(unsigned channels) +{ + assert(channels < Impl::maxChannels); + if (P->fChannels != channels) { + P->fChannels = channels; + clear(); + } +} + +sfzFilterDsp *FilterEq::Impl::getDsp(unsigned channels) +{ + switch (channels) { + default: return nullptr; + + case 1: return &fDsp; + case 2: return &fDsp2ch; + } +} } // namespace sfz diff --git a/src/sfizz/SfzFilter.h b/src/sfizz/SfzFilter.h index a725062d..7b9ac9ae 100644 --- a/src/sfizz/SfzFilter.h +++ b/src/sfizz/SfzFilter.h @@ -13,14 +13,13 @@ enum FilterType : int; /** Multi-mode filter for SFZ v2 - Available for mono and stereo. (NCh=1, NCh=2) + Available for mono and stereo. (channels=1, channels=2) Parameters: `cutoff`: it's the opcode `filN_cutoff` (Hz) `q`: it's the opcode `filN_resonance` (dB) `pksh`: it's the opcode `filN_gain` (dB) */ -template class Filter { public: Filter(); @@ -44,7 +43,7 @@ public: `pksh` is a peak/shelf gain expressed in dB. `in[i]` and `out[i]` may refer to identical buffers, for in-place processing */ - void process(const float *const in[NCh], float *const out[NCh], float cutoff, float q, float pksh, unsigned nframes); + void process(const float *const in[], float *const out[], float cutoff, float q, float pksh, unsigned nframes); /** Process one cycle of the filter with cutoff and Q values varying over time. @@ -53,7 +52,17 @@ public: `pksh` is a peak/shelf gain expressed in dB. `in[i]` and `out[i]` may refer to identical buffers, for in-place processing */ - void processModulated(const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *q, const float *pksh, unsigned nframes); + void processModulated(const float *const in[], float *const out[], const float *cutoff, const float *q, const float *pksh, unsigned nframes); + + /** + Get the number of channels. + */ + unsigned channels() const; + + /** + Set the number of channels. + */ + void setChannels(unsigned channels); /** Get the type of filter. @@ -99,14 +108,13 @@ enum FilterType : int { /** Equalizer filter for SFZ v1 - Available for mono and stereo. (NCh=1, NCh=2) + Available for mono and stereo. (channels=1, channels=2) Parameters: `cutoff`: it's the opcode `egN_freq` (Hz) `bw`: it's the opcode `eqN_bw` (octave) `pksh`: it's the opcode `eqN_gain` (dB) */ -template class FilterEq { public: FilterEq(); @@ -130,7 +138,7 @@ public: `pksh` is a peak/shelf gain expressed in dB. `in[i]` and `out[i]` may refer to identical buffers, for in-place processing */ - void process(const float *const in[NCh], float *const out[NCh], float cutoff, float bw, float pksh, unsigned nframes); + void process(const float *const in[], float *const out[], float cutoff, float bw, float pksh, unsigned nframes); /** Process one cycle of the filter with cutoff and bandwidth values varying over time. @@ -139,7 +147,17 @@ public: `pksh` is a peak/shelf gain expressed in dB. `in[i]` and `out[i]` may refer to identical buffers, for in-place processing */ - void processModulated(const float *const in[NCh], float *const out[NCh], const float *cutoff, const float *bw, const float *pksh, unsigned nframes); + void processModulated(const float *const in[], float *const out[], const float *cutoff, const float *bw, const float *pksh, unsigned nframes); + + /** + Get the number of channels. + */ + unsigned channels() const; + + /** + Set the number of channels. + */ + void setChannels(unsigned channels); private: struct Impl; diff --git a/src/sfizz/SfzFilterImpls.cxx b/src/sfizz/SfzFilterImpls.cxx index 54f529ab..bda6d372 100644 --- a/src/sfizz/SfzFilterImpls.cxx +++ b/src/sfizz/SfzFilterImpls.cxx @@ -4,10 +4,26 @@ // license. You should have receive a LICENSE.md file along with the code. // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz -struct dsp {}; struct Meta {}; struct UI {}; +/** + Base of the faust DSP for filters + */ +struct sfzFilterDsp { +public: + virtual ~sfzFilterDsp() {} + + virtual void init(int) = 0; + virtual void instanceClear() = 0; + virtual void compute(int, float **, float **) = 0; + + virtual void setCutoff(float) {} + virtual void setQ(float) {} + virtual void setBandwidth(float) {} + virtual void setPkShGain(float) {} +}; + #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -72,9 +88,8 @@ struct UI {}; Parameterized by cutoff and Q */ template struct sfzFilter : public F { - void setCutoff(float v) { F::fCutoff = v; } - void setQ(float v) { F::fQ = v; } - void setPkShGain(float) {} + void setCutoff(float v) override { F::fCutoff = v; } + void setQ(float v) override { F::fQ = v; } }; /** @@ -82,9 +97,7 @@ template struct sfzFilter : public F { Parameterized by cutoff only */ template struct sfzFilterNoQ : public F { - void setCutoff(float v) { F::fCutoff = v; } - void setQ(float) {} - void setPkShGain(float) {} + void setCutoff(float v) override { F::fCutoff = v; } }; /** @@ -92,9 +105,6 @@ template struct sfzFilterNoQ : public F { Not parameterized */ template struct sfzFilterNoCutoff : public F { - void setCutoff(float) {} - void setQ(float) {} - void setPkShGain(float) {} }; /** @@ -102,9 +112,9 @@ template struct sfzFilterNoCutoff : public F { Parameterized by cutoff, Q, peak/shelf gain */ template struct sfzFilterPkSh : public F { - void setCutoff(float v) { F::fCutoff = v; } - void setQ(float v) { F::fQ = v; } - void setPkShGain(float v) { F::fPkShGain = v; } + void setCutoff(float v) override { F::fCutoff = v; } + void setQ(float v) override { F::fQ = v; } + void setPkShGain(float v) override { F::fPkShGain = v; } }; /** @@ -112,82 +122,57 @@ template struct sfzFilterPkSh : public F { Parameterized by cutoff, bandwidth, peak/shelf gain */ template struct sfzFilterEq : public F { - void setCutoff(float v) { F::fCutoff = v; } - void setBandwidth(float v) { F::fBandwidth = v; } - void setPkShGain(float v) { F::fPkShGain = v; } + void setCutoff(float v) override { F::fCutoff = v; } + void setBandwidth(float v) override { F::fBandwidth = v; } + void setPkShGain(float v) override { F::fPkShGain = v; } }; -template struct sfzLpf1p; -template struct sfzLpf2p; -template struct sfzLpf4p; -template struct sfzLpf6p; -template struct sfzHpf1p; -template struct sfzHpf2p; -template struct sfzHpf4p; -template struct sfzHpf6p; -template struct sfzBpf1p; -template struct sfzBpf2p; -template struct sfzBpf4p; -template struct sfzBpf6p; -template struct sfzApf1p; -template struct sfzBrf1p; -template struct sfzBrf2p; -template struct sfzPink; -template struct sfzLpf2pSv; -template struct sfzHpf2pSv; -template struct sfzBpf2pSv; -template struct sfzBrf2pSv; -template struct sfzLsh; -template struct sfzHsh; -template struct sfzPeq; -template struct sfzEq; +struct sfzLpf1p final : public sfzFilterNoQ {}; +struct sfzLpf2p final : public sfzFilter {}; +struct sfzLpf4p final : public sfzFilter {}; +struct sfzLpf6p final : public sfzFilter {}; +struct sfzHpf1p final : public sfzFilterNoQ {}; +struct sfzHpf2p final : public sfzFilter {}; +struct sfzHpf4p final : public sfzFilter {}; +struct sfzHpf6p final : public sfzFilter {}; +struct sfzBpf1p final : public sfzFilterNoQ {}; +struct sfzBpf2p final : public sfzFilter {}; +struct sfzBpf4p final : public sfzFilter {}; +struct sfzBpf6p final : public sfzFilter {}; +struct sfzApf1p final : public sfzFilterNoQ {}; +struct sfzBrf1p final : public sfzFilterNoQ {}; +struct sfzBrf2p final : public sfzFilter {}; +struct sfzPink final : public sfzFilterNoCutoff {}; +struct sfzLpf2pSv final : public sfzFilter {}; +struct sfzHpf2pSv final : public sfzFilter {}; +struct sfzBpf2pSv final : public sfzFilter {}; +struct sfzBrf2pSv final : public sfzFilter {}; +struct sfzLsh final : public sfzFilterPkSh {}; +struct sfzHsh final : public sfzFilterPkSh {}; +struct sfzPeq final : public sfzFilterPkSh {}; +struct sfzEq final : public sfzFilterEq {}; -template<> struct sfzLpf1p<1> : public sfzFilterNoQ {}; -template<> struct sfzLpf2p<1> : public sfzFilter {}; -template<> struct sfzLpf4p<1> : public sfzFilter {}; -template<> struct sfzLpf6p<1> : public sfzFilter {}; -template<> struct sfzHpf1p<1> : public sfzFilterNoQ {}; -template<> struct sfzHpf2p<1> : public sfzFilter {}; -template<> struct sfzHpf4p<1> : public sfzFilter {}; -template<> struct sfzHpf6p<1> : public sfzFilter {}; -template<> struct sfzBpf1p<1> : public sfzFilterNoQ {}; -template<> struct sfzBpf2p<1> : public sfzFilter {}; -template<> struct sfzBpf4p<1> : public sfzFilter {}; -template<> struct sfzBpf6p<1> : public sfzFilter {}; -template<> struct sfzApf1p<1> : public sfzFilterNoQ {}; -template<> struct sfzBrf1p<1> : public sfzFilterNoQ {}; -template<> struct sfzBrf2p<1> : public sfzFilter {}; -template<> struct sfzPink<1> : public sfzFilterNoCutoff {}; -template<> struct sfzLpf2pSv<1> : public sfzFilter {}; -template<> struct sfzHpf2pSv<1> : public sfzFilter {}; -template<> struct sfzBpf2pSv<1> : public sfzFilter {}; -template<> struct sfzBrf2pSv<1> : public sfzFilter {}; -template<> struct sfzLsh<1> : public sfzFilterPkSh {}; -template<> struct sfzHsh<1> : public sfzFilterPkSh {}; -template<> struct sfzPeq<1> : public sfzFilterPkSh {}; -template<> struct sfzEq<1> : public sfzFilterEq {}; - -template<> struct sfzLpf1p<2> : public sfzFilterNoQ {}; -template<> struct sfzLpf2p<2> : public sfzFilter {}; -template<> struct sfzLpf4p<2> : public sfzFilter {}; -template<> struct sfzLpf6p<2> : public sfzFilter {}; -template<> struct sfzHpf1p<2> : public sfzFilterNoQ {}; -template<> struct sfzHpf2p<2> : public sfzFilter {}; -template<> struct sfzHpf4p<2> : public sfzFilter {}; -template<> struct sfzHpf6p<2> : public sfzFilter {}; -template<> struct sfzBpf1p<2> : public sfzFilterNoQ {}; -template<> struct sfzBpf2p<2> : public sfzFilter {}; -template<> struct sfzBpf4p<2> : public sfzFilter {}; -template<> struct sfzBpf6p<2> : public sfzFilter {}; -template<> struct sfzApf1p<2> : public sfzFilterNoQ {}; -template<> struct sfzBrf1p<2> : public sfzFilterNoQ {}; -template<> struct sfzBrf2p<2> : public sfzFilter {}; -template<> struct sfzPink<2> : public sfzFilterNoCutoff {}; -template<> struct sfzLpf2pSv<2> : public sfzFilter {}; -template<> struct sfzHpf2pSv<2> : public sfzFilter {}; -template<> struct sfzBpf2pSv<2> : public sfzFilter {}; -template<> struct sfzBrf2pSv<2> : public sfzFilter {}; -template<> struct sfzLsh<2> : public sfzFilterPkSh {}; -template<> struct sfzHsh<2> : public sfzFilterPkSh {}; -template<> struct sfzPeq<2> : public sfzFilterPkSh {}; -template<> struct sfzEq<2> : public sfzFilterEq {}; +struct sfz2chLpf1p final : public sfzFilterNoQ {}; +struct sfz2chLpf2p final : public sfzFilter {}; +struct sfz2chLpf4p final : public sfzFilter {}; +struct sfz2chLpf6p final : public sfzFilter {}; +struct sfz2chHpf1p final : public sfzFilterNoQ {}; +struct sfz2chHpf2p final : public sfzFilter {}; +struct sfz2chHpf4p final : public sfzFilter {}; +struct sfz2chHpf6p final : public sfzFilter {}; +struct sfz2chBpf1p final : public sfzFilterNoQ {}; +struct sfz2chBpf2p final : public sfzFilter {}; +struct sfz2chBpf4p final : public sfzFilter {}; +struct sfz2chBpf6p final : public sfzFilter {}; +struct sfz2chApf1p final : public sfzFilterNoQ {}; +struct sfz2chBrf1p final : public sfzFilterNoQ {}; +struct sfz2chBrf2p final : public sfzFilter {}; +struct sfz2chPink final : public sfzFilterNoCutoff {}; +struct sfz2chLpf2pSv final : public sfzFilter {}; +struct sfz2chHpf2pSv final : public sfzFilter {}; +struct sfz2chBpf2pSv final : public sfzFilter {}; +struct sfz2chBrf2pSv final : public sfzFilter {}; +struct sfz2chLsh final : public sfzFilterPkSh {}; +struct sfz2chHsh final : public sfzFilterPkSh {}; +struct sfz2chPeq final : public sfzFilterPkSh {}; +struct sfz2chEq final : public sfzFilterEq {};