diff --git a/src/sfizz/SfzFilter.cpp b/src/sfizz/SfzFilter.cpp index 3a16bc31..8c023dfc 100644 --- a/src/sfizz/SfzFilter.cpp +++ b/src/sfizz/SfzFilter.cpp @@ -13,6 +13,9 @@ namespace sfz { +//------------------------------------------------------------------------------ +// SFZ v2 multi-mode filter + template struct Filter::Impl { FilterType fType = kFilterNone; @@ -246,4 +249,84 @@ void Filter::setType(FilterType type) template class Filter<1>; template class Filter<2>; +//------------------------------------------------------------------------------ +// SFZ v1 equalizer filter + + +template +struct FilterEq::Impl { + sfzEq fDsp; +}; + +template +FilterEq::FilterEq() + : P{new Impl} +{ +} + +template +FilterEq::~FilterEq() +{ +} + +template +void FilterEq::init(double sampleRate) +{ + sfzEq &filter = P->fDsp; + + filter.init(sampleRate); +} + +template +void FilterEq::clear() +{ + sfzEq &filter = P->fDsp; + + filter.instanceClear(); +} + +template +void FilterEq::process(const float *const in[NCh], float *const out[NCh], float cutoff, float bw, float pksh, unsigned nframes) +{ + sfzEq &filter = P->fDsp; + + filter.setCutoff(cutoff); + filter.setBandwidth(bw); + filter.setPkShGain(pksh); + filter.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) +{ + sfzEq &filter = P->fDsp; + + 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]; + + for (unsigned c = 0; c < NCh; ++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)); + + frame += current; + } +} + +template class FilterEq<1>; +template class FilterEq<2>; + } // namespace sfz diff --git a/src/sfizz/SfzFilter.h b/src/sfizz/SfzFilter.h index d9c36286..a725062d 100644 --- a/src/sfizz/SfzFilter.h +++ b/src/sfizz/SfzFilter.h @@ -97,4 +97,53 @@ enum FilterType : int { kFilterPeq, }; +/** + Equalizer filter for SFZ v1 + Available for mono and stereo. (NCh=1, NCh=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(); + ~FilterEq(); + + /** + Set up the filter constants. + Run it exactly once after instantiating. + */ + void init(double sampleRate); + + /** + Reinitialize the filter memory to zeros. + */ + void clear(); + + /** + Process one cycle of the filter without modulating cutoff or bandwidth. + `cutoff` is a frequency expressed in Hz. + `bw` is a bandwidth expressed in octaves. + `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); + + /** + Process one cycle of the filter with cutoff and bandwidth values varying over time. + `cutoff` is a frequency expressed in Hz. + `bw` is a bandwidth expressed in octaves. + `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); + +private: + struct Impl; + std::unique_ptr P; +}; + } // namespace sfz diff --git a/src/sfizz/SfzFilterImpls.cxx b/src/sfizz/SfzFilterImpls.cxx index a7c86de6..54f529ab 100644 --- a/src/sfizz/SfzFilterImpls.cxx +++ b/src/sfizz/SfzFilterImpls.cxx @@ -36,6 +36,7 @@ struct UI {}; #include "gen/filters/sfzLsh.cxx" #include "gen/filters/sfzHsh.cxx" #include "gen/filters/sfzPeq.cxx" +#include "gen/filters/sfzEq.cxx" #include "gen/filters/sfz2chApf1p.cxx" #include "gen/filters/sfz2chBpf1p.cxx" @@ -60,6 +61,7 @@ struct UI {}; #include "gen/filters/sfz2chLsh.cxx" #include "gen/filters/sfz2chHsh.cxx" #include "gen/filters/sfz2chPeq.cxx" +#include "gen/filters/sfz2chEq.cxx" #if defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic pop @@ -105,6 +107,16 @@ template struct sfzFilterPkSh : public F { void setPkShGain(float v) { F::fPkShGain = v; } }; +/** + Wrapper of equalizer filters with a bandwidth control + 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; } +}; + template struct sfzLpf1p; template struct sfzLpf2p; template struct sfzLpf4p; @@ -128,6 +140,7 @@ template struct sfzBrf2pSv; template struct sfzLsh; template struct sfzHsh; template struct sfzPeq; +template struct sfzEq; template<> struct sfzLpf1p<1> : public sfzFilterNoQ {}; template<> struct sfzLpf2p<1> : public sfzFilter {}; @@ -152,6 +165,7 @@ 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 {}; @@ -176,3 +190,4 @@ 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 {};