From bfbbc6085b4a4cb2ee31f357c26570d9521e04d7 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Mar 2020 14:27:39 +0100 Subject: [PATCH] Add the filter effect --- src/CMakeLists.txt | 1 + src/sfizz/Effects.cpp | 2 + src/sfizz/effects/Filter.cpp | 101 +++++++++++++++++++++++++++++++++++ src/sfizz/effects/Filter.h | 55 +++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 src/sfizz/effects/Filter.cpp create mode 100644 src/sfizz/effects/Filter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b22a2b2..6113c8b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,7 @@ set (SFIZZ_SOURCES sfizz/SfzFilter.cpp sfizz/Effects.cpp sfizz/effects/Nothing.cpp + sfizz/effects/Filter.cpp sfizz/effects/Lofi.cpp ) include (SfizzSIMDSourceFiles) diff --git a/src/sfizz/Effects.cpp b/src/sfizz/Effects.cpp index 512f2b5e..78159d4e 100644 --- a/src/sfizz/Effects.cpp +++ b/src/sfizz/Effects.cpp @@ -10,6 +10,7 @@ #include "SIMDHelpers.h" #include "Config.h" #include "effects/Nothing.h" +#include "effects/Filter.h" #include "effects/Lofi.h" #include @@ -18,6 +19,7 @@ namespace sfz { void EffectFactory::registerStandardEffectTypes() { // TODO + registerEffectType("filter", fx::Filter::makeInstance); registerEffectType("lofi", fx::Lofi::makeInstance); } diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp new file mode 100644 index 00000000..1303132e --- /dev/null +++ b/src/sfizz/effects/Filter.cpp @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// 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 + + +/** + Note(jpc): implementation status + +- [x] filter_type +- [x] filter_cutoff +- [ ] filter_cutoff_oncc +- [x] filter_resonance +- [ ] filter_resonance_oncc + +Potential extensions (like ARIA) +- [/] filter_gain +- [ ] filter_gain_oncc + + */ + +#include "Filter.h" +#include "Opcode.h" +#include "SIMDHelpers.h" +#include "Debug.h" +#include "absl/memory/memory.h" + +namespace sfz { +namespace fx { + Filter::Filter(const FilterDescription& desc) + : _desc(desc) + { + _filter.setType(desc.type); + _filter.setChannels(2); + } + + void Filter::setSampleRate(double sampleRate) + { + _filter.init(sampleRate); + _filter.clear(); + } + + void Filter::setSamplesPerBlock(int samplesPerBlock) + { + _tempBuffer.resize(samplesPerBlock); + } + + void Filter::clear() + { + _filter.clear(); + } + + void Filter::process(const float* const inputs[], float* const outputs[], unsigned nframes) + { + absl::Span cutoff = _tempBuffer.getSpan(0).first(nframes); + absl::Span q = _tempBuffer.getSpan(1).first(nframes); + absl::Span pksh = _tempBuffer.getSpan(2).first(nframes); + + sfz::fill(cutoff, _desc.cutoff); + sfz::fill(q, _desc.resonance); + sfz::fill(pksh, _desc.gain); + + _filter.processModulated(inputs, outputs, cutoff.data(), q.data(), pksh.data(), nframes); + } + + std::unique_ptr Filter::makeInstance(absl::Span members) + { + FilterDescription desc; + + for (const Opcode& opc : members) { + switch (hash(opc.value)) { + case hash("filter_cutoff"): + setValueFromOpcode(opc, desc.cutoff, Default::filterCutoffRange); + break; + case hash("filter_resonance"): + setValueFromOpcode(opc, desc.resonance, Default::filterResonanceRange); + break; + case hash("filter_type"): + { + absl::optional ftype = sfz::Filter::typeFromName(opc.value); + if (ftype) + desc.type = *ftype; + else { + desc.type = FilterType::kFilterNone; + DBG("Unknown filter type: " << std::string(opcode.value)); + } + break; + } + // extension + case hash("sfizz:filter_gain"): + setValueFromOpcode(opc, desc.gain, Default::filterGainRange); + break; + } + } + + return absl::make_unique(desc); + } + +} // namespace fx +} // namespace sfz diff --git a/src/sfizz/effects/Filter.h b/src/sfizz/effects/Filter.h new file mode 100644 index 00000000..c3265667 --- /dev/null +++ b/src/sfizz/effects/Filter.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// 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 + +#pragma once +#include "Effects.h" +#include "FilterDescription.h" +#include "SfzFilter.h" + +namespace sfz { +namespace fx { + + /** + * @brief Effect which passes signal through a filter + */ + class Filter : public Effect { + public: + explicit Filter(const FilterDescription& desc); + + /** + * @brief Initializes with the given sample rate. + */ + void setSampleRate(double sampleRate) override; + + /** + * @brief Sets the maximum number of frames to render at a time. The actual + * value can be lower but should never be higher. + */ + void setSamplesPerBlock(int samplesPerBlock) override; + + /** + * @brief Reset the state to initial. + */ + void clear() override; + + /** + * @brief Copy the input signal to the output + */ + void process(const float* const inputs[], float* const outputs[], unsigned nframes) override; + + /** + * @brief Instantiates given the contents of the block. + */ + static std::unique_ptr makeInstance(absl::Span members); + + private: + sfz::Filter _filter; + FilterDescription _desc; + AudioBuffer _tempBuffer { 3, config::defaultSamplesPerBlock }; + }; + +} // namespace fx +} // namespace sfz