From 43262395c9bd7edb2585c042bc74dd385e83bb99 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 12 Mar 2020 14:49:31 +0100 Subject: [PATCH] Add the EQ effect --- src/CMakeLists.txt | 1 + src/sfizz/Effects.cpp | 2 + src/sfizz/effects/Eq.cpp | 98 ++++++++++++++++++++++++++++++++++++++++ src/sfizz/effects/Eq.h | 55 ++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 src/sfizz/effects/Eq.cpp create mode 100644 src/sfizz/effects/Eq.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6113c8b0..14d469f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ set (SFIZZ_SOURCES sfizz/Effects.cpp sfizz/effects/Nothing.cpp sfizz/effects/Filter.cpp + sfizz/effects/Eq.cpp sfizz/effects/Lofi.cpp ) include (SfizzSIMDSourceFiles) diff --git a/src/sfizz/Effects.cpp b/src/sfizz/Effects.cpp index 78159d4e..71494d1d 100644 --- a/src/sfizz/Effects.cpp +++ b/src/sfizz/Effects.cpp @@ -11,6 +11,7 @@ #include "Config.h" #include "effects/Nothing.h" #include "effects/Filter.h" +#include "effects/Eq.h" #include "effects/Lofi.h" #include @@ -20,6 +21,7 @@ void EffectFactory::registerStandardEffectTypes() { // TODO registerEffectType("filter", fx::Filter::makeInstance); + registerEffectType("eq", fx::Eq::makeInstance); registerEffectType("lofi", fx::Lofi::makeInstance); } diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp new file mode 100644 index 00000000..2e4ad052 --- /dev/null +++ b/src/sfizz/effects/Eq.cpp @@ -0,0 +1,98 @@ +// 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] eq_type +- [x] eq_freq +- [ ] eq_freq_oncc +- [x] eq_bw +- [ ] eq_bw_oncc +- [x] eq_gain +- [ ] eq_gain_oncc + + */ + +#include "Eq.h" +#include "Opcode.h" +#include "SIMDHelpers.h" +#include "Debug.h" +#include "absl/memory/memory.h" + +namespace sfz { +namespace fx { + Eq::Eq(const EQDescription& desc) + : _desc(desc) + { + _filter.setType(desc.type); + _filter.setChannels(2); + } + + void Eq::setSampleRate(double sampleRate) + { + _filter.init(sampleRate); + _filter.clear(); + } + + void Eq::setSamplesPerBlock(int samplesPerBlock) + { + _tempBuffer.resize(samplesPerBlock); + } + + void Eq::clear() + { + _filter.clear(); + } + + void Eq::process(const float* const inputs[], float* const outputs[], unsigned nframes) + { + absl::Span cutoff = _tempBuffer.getSpan(0).first(nframes); + absl::Span bw = _tempBuffer.getSpan(1).first(nframes); + absl::Span pksh = _tempBuffer.getSpan(2).first(nframes); + + sfz::fill(cutoff, _desc.frequency); + sfz::fill(bw, _desc.bandwidth); + sfz::fill(pksh, _desc.gain); + + _filter.processModulated(inputs, outputs, cutoff.data(), bw.data(), pksh.data(), nframes); + } + + std::unique_ptr Eq::makeInstance(absl::Span members) + { + EQDescription desc; + + for (const Opcode& opc : members) { + switch (hash(opc.value)) { + case hash("eq_freq"): + setValueFromOpcode(opc, desc.frequency, Default::eqFrequencyRange); + break; + case hash("eq_bw"): + setValueFromOpcode(opc, desc.bandwidth, Default::eqBandwidthRange); + break; + case hash("eq_gain"): + setValueFromOpcode(opc, desc.gain, Default::eqGainRange); + break; + case hash("eq_type"): + { + absl::optional ftype = sfz::FilterEq::typeFromName(opc.value); + if (ftype) + desc.type = *ftype; + else { + desc.type = EqType::kEqNone; + DBG("Unknown EQ type: " << std::string(opcode.value)); + } + break; + } + } + } + + return absl::make_unique(desc); + } + +} // namespace fx +} // namespace sfz diff --git a/src/sfizz/effects/Eq.h b/src/sfizz/effects/Eq.h new file mode 100644 index 00000000..0c94cc9a --- /dev/null +++ b/src/sfizz/effects/Eq.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 "EQDescription.h" +#include "SfzFilter.h" + +namespace sfz { +namespace fx { + + /** + * @brief Effect which passes signal through a filter + */ + class Eq : public Effect { + public: + explicit Eq(const EQDescription& 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::FilterEq _filter; + EQDescription _desc; + AudioBuffer _tempBuffer { 3, config::defaultSamplesPerBlock }; + }; + +} // namespace fx +} // namespace sfz