From ec62051de1e9e589ac242ab54396199f54e87c50 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Thu, 14 Jan 2021 15:35:12 -0500 Subject: [PATCH 01/11] setup --- Makefile | 1 + daisysp.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 52a38110..30202ba4 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ compressor \ crossfade \ dcblock \ decimator \ +diffuser \ drip \ fm2 \ fold \ diff --git a/daisysp.h b/daisysp.h index 975dc540..04bfa666 100644 --- a/daisysp.h +++ b/daisysp.h @@ -31,6 +31,7 @@ #include "modules/dcblock.h" #include "modules/decimator.h" #include "modules/delayline.h" +#include "modules/diffuser.h" #include "modules/drip.h" #include "modules/dsp.h" #include "modules/fm2.h" From 8cbba0b753566d9c6748ea69d1c85647cdcd4cfd Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Thu, 14 Jan 2021 15:36:27 -0500 Subject: [PATCH 02/11] more setup --- modules/diffuser.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++ modules/diffuser.h | 39 ++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 modules/diffuser.cpp create mode 100644 modules/diffuser.h diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp new file mode 100644 index 00000000..8df18232 --- /dev/null +++ b/modules/diffuser.cpp @@ -0,0 +1,67 @@ +#include "dsp.h" +#include "diffuser.h" +#include + +using namespace daisysp; + +void Diffuser::Init(uint16_t* buffer) +{ + engine_.Init(buffer); + engine_.SetLFOFrequency(LFO_1, 0.3f / 48000.0f); + lp_decay_ = 0.0f; +} + +void Diffuser::Clear() +{ + engine_.Clear(); +} + +void Diffuser::Process(float amount, float rt, float* in_out, size_t size) +{ + typedef E::Reserve< + 126, + E::Reserve< + 180, + E::Reserve< + 269, + E::Reserve< + 444, + E::Reserve<1653, E::Reserve<2010, E::Reserve<3411>>>>>>> + Memory; + E::DelayLine ap1; + E::DelayLine ap2; + E::DelayLine ap3; + E::DelayLine ap4; + E::DelayLine dapa; + E::DelayLine dapb; + E::DelayLine del; + E::Context c; + const float kap = 0.625f; + const float klp = 0.75f; + float lp = lp_decay_; + while(size--) + { + float wet; + engine_.Start(&c); + c.Read(*in_out); + c.Read(ap1 TAIL, kap); + c.WriteAllPass(ap1, -kap); + c.Read(ap2 TAIL, kap); + c.WriteAllPass(ap2, -kap); + c.Read(ap3 TAIL, kap); + c.WriteAllPass(ap3, -kap); + c.Interpolate(ap4, 400.0f, LFO_1, 43.0f, kap); + c.WriteAllPass(ap4, -kap); + c.Interpolate(del, 3070.0f, LFO_1, 340.0f, rt); + c.Lp(lp, klp); + c.Read(dapa TAIL, -kap); + c.WriteAllPass(dapa, kap); + c.Read(dapb TAIL, kap); + c.WriteAllPass(dapb, -kap); + c.Write(del, 2.0f); + c.Write(wet, 0.0f); + *in_out += amount * (wet - *in_out); + ++in_out; + } + lp_decay_ = lp; +} diff --git a/modules/diffuser.h b/modules/diffuser.h new file mode 100644 index 00000000..3905cf2c --- /dev/null +++ b/modules/diffuser.h @@ -0,0 +1,39 @@ +#pragma once +#ifndef DSY_DIFFUSER_H +#define DSY_DIFFUSER_H + +#include +#ifdef __cplusplus + +/** @file diffuser.h */ + +namespace daisysp +{ +/** + @brief Granular Diffuser + @author Ben Sergentanis + @date Jan 2021 + Ported from pichenettes/eurorack/plaits/dsp/fx/diffuser.h \n + to an independent module. \n + Original code written by Emilie Gillet in 2016. \n +*/ +class Diffuser +{ + public: + Diffuser() {} + ~Diffuser() {} + + void Init(uint16_t* buffer); + + void Clear() { engine_.Clear(); } + + void Process(float amount, float rt, float* in_out, size_t size); + + private: + typedef FxEngine<8192, FORMAT_12_BIT> E; + E engine_; + float lp_decay_; +}; +} // namespace daisysp +#endif +#endif \ No newline at end of file From a17cf4e77c575288f0c20d61a20ec26962c5e528 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Thu, 14 Jan 2021 15:52:57 -0500 Subject: [PATCH 03/11] idk --- modules/diffuser.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index 8df18232..d79d0f1a 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -18,16 +18,7 @@ void Diffuser::Clear() void Diffuser::Process(float amount, float rt, float* in_out, size_t size) { - typedef E::Reserve< - 126, - E::Reserve< - 180, - E::Reserve< - 269, - E::Reserve< - 444, - E::Reserve<1653, E::Reserve<2010, E::Reserve<3411>>>>>>> - Memory; + typedef E::Reserve<126, E::Reserve<180, E::Reserve<269, E::Reserve<444,E::Reserve<1653, E::Reserve<2010, E::Reserve<3411>>>>>>> Memory; E::DelayLine ap1; E::DelayLine ap2; E::DelayLine ap3; From bff65508509e4acf225bb8dfba5ec99386857ca1 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 13:30:02 -0500 Subject: [PATCH 04/11] enging --- daisysp.h | 1 + modules/diffuser.h | 2 + modules/fx_engine.h | 295 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 modules/fx_engine.h diff --git a/daisysp.h b/daisysp.h index 04bfa666..b3dbbc85 100644 --- a/daisysp.h +++ b/daisysp.h @@ -37,6 +37,7 @@ #include "modules/fm2.h" #include "modules/fold.h" #include "modules/formantosc.h" +#include "modules/fx_engine.h" #include "modules/grainlet.h" #include "modules/harmonic_osc.h" #include "modules/jitter.h" diff --git a/modules/diffuser.h b/modules/diffuser.h index 3905cf2c..694f4a68 100644 --- a/modules/diffuser.h +++ b/modules/diffuser.h @@ -2,6 +2,8 @@ #ifndef DSY_DIFFUSER_H #define DSY_DIFFUSER_H +#include "modules/fx_engine.h" + #include #ifdef __cplusplus diff --git a/modules/fx_engine.h b/modules/fx_engine.h new file mode 100644 index 00000000..a5fff39c --- /dev/null +++ b/modules/fx_engine.h @@ -0,0 +1,295 @@ +// Copyright 2014 Emilie Gillet. +// +// Author: Emilie Gillet (emilie.o.gillet@gmail.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// See http://creativecommons.org/licenses/MIT/ for more information. +// +// ----------------------------------------------------------------------------- +// +// Base class for building reverbs. + +#ifndef DSY_FX_ENGINE_H +#define DSY_FX_ENGINE_H + +#include + +namespace daisysp { + +#define TAIL , -1 + +enum Format { + FORMAT_12_BIT, + FORMAT_16_BIT, + FORMAT_32_BIT +}; + +enum LFOIndex { + LFO_1, + LFO_2 +}; + +template +struct DataType { }; + +template<> +struct DataType { + typedef uint16_t T; + + static inline float Decompress(T value) { + return static_cast(static_cast(value)) / 4096.0f; + } + + static inline T Compress(float value) { + return static_cast( + stmlib::Clip16(static_cast(value * 4096.0f))); + } +}; + +template<> +struct DataType { + typedef uint16_t T; + + static inline float Decompress(T value) { + return static_cast(static_cast(value)) / 32768.0f; + } + + static inline T Compress(float value) { + return static_cast( + stmlib::Clip16(static_cast(value * 32768.0f))); + } +}; + +template<> +struct DataType { + typedef float T; + + static inline float Decompress(T value) { + return value;; + } + + static inline T Compress(float value) { + return value; + } +}; + +template< + size_t size, + Format format = FORMAT_12_BIT> +class FxEngine { + public: + typedef typename DataType::T T; + FxEngine() { } + ~FxEngine() { } + + void Init(T* buffer) { + buffer_ = buffer; + } + + void Clear() { + std::fill(&buffer_[0], &buffer_[size], 0); + write_ptr_ = 0; + } + + struct Empty { }; + + template + struct Reserve { + typedef T Tail; + enum { + length = l + }; + }; + + template + struct DelayLine { + enum { + length = DelayLine::length, + base = DelayLine::base + DelayLine::length + 1 + }; + }; + + template + struct DelayLine { + enum { + length = Memory::length, + base = 0 + }; + }; + + class Context { + friend class FxEngine; + public: + Context() { } + ~Context() { } + + inline void Load(float value) { + accumulator_ = value; + } + + inline void Read(float value, float scale) { + accumulator_ += value * scale; + } + + inline void Read(float value) { + accumulator_ += value; + } + + inline void Write(float& value) { + value = accumulator_; + } + + inline void Write(float& value, float scale) { + value = accumulator_; + accumulator_ *= scale; + } + + template + inline void Write(D& d, int32_t offset, float scale) { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + T w = DataType::Compress(accumulator_); + if (offset == -1) { + buffer_[(write_ptr_ + D::base + D::length - 1) & MASK] = w; + } else { + buffer_[(write_ptr_ + D::base + offset) & MASK] = w; + } + accumulator_ *= scale; + } + + template + inline void Write(D& d, float scale) { + Write(d, 0, scale); + } + + template + inline void WriteAllPass(D& d, int32_t offset, float scale) { + Write(d, offset, scale); + accumulator_ += previous_read_; + } + + template + inline void WriteAllPass(D& d, float scale) { + WriteAllPass(d, 0, scale); + } + + template + inline void Read(D& d, int32_t offset, float scale) { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + T r; + if (offset == -1) { + r = buffer_[(write_ptr_ + D::base + D::length - 1) & MASK]; + } else { + r = buffer_[(write_ptr_ + D::base + offset) & MASK]; + } + float r_f = DataType::Decompress(r); + previous_read_ = r_f; + accumulator_ += r_f * scale; + } + + template + inline void Read(D& d, float scale) { + Read(d, 0, scale); + } + + inline void Lp(float& state, float coefficient) { + state += coefficient * (accumulator_ - state); + accumulator_ = state; + } + + inline void Hp(float& state, float coefficient) { + state += coefficient * (accumulator_ - state); + accumulator_ -= state; + } + + template + inline void Interpolate(D& d, float offset, float scale) { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + MAKE_INTEGRAL_FRACTIONAL(offset); + float a = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); + float b = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); + float x = a + (b - a) * offset_fractional; + previous_read_ = x; + accumulator_ += x * scale; + } + + template + inline void Interpolate( + D& d, float offset, LFOIndex index, float amplitude, float scale) { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + offset += amplitude * lfo_value_[index]; + MAKE_INTEGRAL_FRACTIONAL(offset); + float a = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); + float b = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); + float x = a + (b - a) * offset_fractional; + previous_read_ = x; + accumulator_ += x * scale; + } + + private: + float accumulator_; + float previous_read_; + float lfo_value_[2]; + T* buffer_; + int32_t write_ptr_; + + DISALLOW_COPY_AND_ASSIGN(Context); + }; + + inline void SetLFOFrequency(LFOIndex index, float frequency) { + lfo_[index].template Init(frequency * 32.0f); + } + + inline void Start(Context* c) { + --write_ptr_; + if (write_ptr_ < 0) { + write_ptr_ += size; + } + c->accumulator_ = 0.0f; + c->previous_read_ = 0.0f; + c->buffer_ = buffer_; + c->write_ptr_ = write_ptr_; + if ((write_ptr_ & 31) == 0) { + c->lfo_value_[0] = lfo_[0].Next(); + c->lfo_value_[1] = lfo_[1].Next(); + } else { + c->lfo_value_[0] = lfo_[0].value(); + c->lfo_value_[1] = lfo_[1].value(); + } + } + + private: + enum { + MASK = size - 1 + }; + + int32_t write_ptr_; + T* buffer_; + stmlib::CosineOscillator lfo_[2]; + + DISALLOW_COPY_AND_ASSIGN(FxEngine); +}; + +} // namespace plaits + +#endif // PLAITS_DSP_FX_FX_ENGINE_H_ \ No newline at end of file From d6b6daac4a2149d997588a89e8b820343c25c3d7 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 14:10:08 -0500 Subject: [PATCH 05/11] building --- modules/diffuser.cpp | 16 +- modules/diffuser.h | 2 +- modules/fx_engine.h | 596 ++++++++++++++++++++++++++----------------- 3 files changed, 371 insertions(+), 243 deletions(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index d79d0f1a..5758edb6 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -11,14 +11,18 @@ void Diffuser::Init(uint16_t* buffer) lp_decay_ = 0.0f; } -void Diffuser::Clear() -{ - engine_.Clear(); -} - void Diffuser::Process(float amount, float rt, float* in_out, size_t size) { - typedef E::Reserve<126, E::Reserve<180, E::Reserve<269, E::Reserve<444,E::Reserve<1653, E::Reserve<2010, E::Reserve<3411>>>>>>> Memory; + typedef E::Reserve< + 126, + E::Reserve< + 180, + E::Reserve< + 269, + E::Reserve< + 444, + E::Reserve<1653, E::Reserve<2010, E::Reserve<3411>>>>>>> + Memory; E::DelayLine ap1; E::DelayLine ap2; E::DelayLine ap3; diff --git a/modules/diffuser.h b/modules/diffuser.h index 694f4a68..9ab8c179 100644 --- a/modules/diffuser.h +++ b/modules/diffuser.h @@ -30,7 +30,7 @@ class Diffuser void Clear() { engine_.Clear(); } void Process(float amount, float rt, float* in_out, size_t size); - + private: typedef FxEngine<8192, FORMAT_12_BIT> E; E engine_; diff --git a/modules/fx_engine.h b/modules/fx_engine.h index a5fff39c..8e7b90d3 100644 --- a/modules/fx_engine.h +++ b/modules/fx_engine.h @@ -8,10 +8,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -19,277 +19,401 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -// +// // See http://creativecommons.org/licenses/MIT/ for more information. // // ----------------------------------------------------------------------------- // // Base class for building reverbs. +#pragma once #ifndef DSY_FX_ENGINE_H #define DSY_FX_ENGINE_H #include +#include +#ifdef __cplusplus -namespace daisysp { +#define JOIN(lhs, rhs) JOIN_1(lhs, rhs) +#define JOIN_1(lhs, rhs) JOIN_2(lhs, rhs) +#define JOIN_2(lhs, rhs) lhs##rhs -#define TAIL , -1 +#define STATIC_ASSERT(expression, message) \ + struct JOIN(__static_assertion_at_line_, __LINE__) \ + { \ + impl::StaticAssertion((expression))> \ + JOIN(JOIN(JOIN(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), _), \ + message); \ + }; -enum Format { - FORMAT_12_BIT, - FORMAT_16_BIT, - FORMAT_32_BIT -}; +namespace impl +{ +template +struct StaticAssertion; -enum LFOIndex { - LFO_1, - LFO_2 -}; +template <> +struct StaticAssertion +{ +}; // StaticAssertion + +template +struct StaticAssertionTest +{ +}; // StaticAssertionTest + +} // namespace impl + +namespace daisysp +{ +#define TAIL , -1 -template -struct DataType { }; - -template<> -struct DataType { - typedef uint16_t T; - - static inline float Decompress(T value) { - return static_cast(static_cast(value)) / 4096.0f; - } - - static inline T Compress(float value) { - return static_cast( - stmlib::Clip16(static_cast(value * 4096.0f))); - } +enum Format +{ + FORMAT_12_BIT, + FORMAT_16_BIT, + FORMAT_32_BIT }; -template<> -struct DataType { - typedef uint16_t T; - - static inline float Decompress(T value) { - return static_cast(static_cast(value)) / 32768.0f; - } - - static inline T Compress(float value) { - return static_cast( - stmlib::Clip16(static_cast(value * 32768.0f))); - } +enum LFOIndex +{ + LFO_1, + LFO_2 }; -template<> -struct DataType { - typedef float T; - - static inline float Decompress(T value) { - return value;; - } - - static inline T Compress(float value) { - return value; - } +static inline int32_t Clip16(int32_t x) +{ + if(x < -32768) + { + return -32768; + } + else if(x > 32767) + { + return 32767; + } + else + { + return x; + } +} + +template +struct DataType +{ }; -template< - size_t size, - Format format = FORMAT_12_BIT> -class FxEngine { - public: - typedef typename DataType::T T; - FxEngine() { } - ~FxEngine() { } - - void Init(T* buffer) { - buffer_ = buffer; - } - - void Clear() { - std::fill(&buffer_[0], &buffer_[size], 0); - write_ptr_ = 0; - } - - struct Empty { }; - - template - struct Reserve { - typedef T Tail; - enum { - length = l - }; - }; - - template - struct DelayLine { - enum { - length = DelayLine::length, - base = DelayLine::base + DelayLine::length + 1 - }; - }; +template <> +struct DataType +{ + typedef uint16_t T; - template - struct DelayLine { - enum { - length = Memory::length, - base = 0 - }; - }; - - class Context { - friend class FxEngine; - public: - Context() { } - ~Context() { } - - inline void Load(float value) { - accumulator_ = value; + static inline float Decompress(T value) + { + return static_cast(static_cast(value)) / 4096.0f; } - inline void Read(float value, float scale) { - accumulator_ += value * scale; + static inline T Compress(float value) + { + return static_cast( + Clip16(static_cast(value * 4096.0f))); } +}; - inline void Read(float value) { - accumulator_ += value; - } +template <> +struct DataType +{ + typedef uint16_t T; - inline void Write(float& value) { - value = accumulator_; + static inline float Decompress(T value) + { + return static_cast(static_cast(value)) / 32768.0f; } - inline void Write(float& value, float scale) { - value = accumulator_; - accumulator_ *= scale; - } - - template - inline void Write(D& d, int32_t offset, float scale) { - STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); - T w = DataType::Compress(accumulator_); - if (offset == -1) { - buffer_[(write_ptr_ + D::base + D::length - 1) & MASK] = w; - } else { - buffer_[(write_ptr_ + D::base + offset) & MASK] = w; - } - accumulator_ *= scale; - } - - template - inline void Write(D& d, float scale) { - Write(d, 0, scale); + static inline T Compress(float value) + { + return static_cast( + Clip16(static_cast(value * 32768.0f))); } +}; - template - inline void WriteAllPass(D& d, int32_t offset, float scale) { - Write(d, offset, scale); - accumulator_ += previous_read_; - } - - template - inline void WriteAllPass(D& d, float scale) { - WriteAllPass(d, 0, scale); - } - - template - inline void Read(D& d, int32_t offset, float scale) { - STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); - T r; - if (offset == -1) { - r = buffer_[(write_ptr_ + D::base + D::length - 1) & MASK]; - } else { - r = buffer_[(write_ptr_ + D::base + offset) & MASK]; - } - float r_f = DataType::Decompress(r); - previous_read_ = r_f; - accumulator_ += r_f * scale; - } - - template - inline void Read(D& d, float scale) { - Read(d, 0, scale); - } - - inline void Lp(float& state, float coefficient) { - state += coefficient * (accumulator_ - state); - accumulator_ = state; - } +template <> +struct DataType +{ + typedef float T; - inline void Hp(float& state, float coefficient) { - state += coefficient * (accumulator_ - state); - accumulator_ -= state; + static inline float Decompress(T value) + { + return value; + ; } - - template - inline void Interpolate(D& d, float offset, float scale) { - STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); - MAKE_INTEGRAL_FRACTIONAL(offset); - float a = DataType::Decompress( - buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); - float b = DataType::Decompress( - buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); - float x = a + (b - a) * offset_fractional; - previous_read_ = x; - accumulator_ += x * scale; + + static inline T Compress(float value) { return value; } +}; + +template +class FxEngine +{ + public: + typedef typename DataType::T T; + FxEngine() {} + ~FxEngine() {} + + void Init(T* buffer) + { + buffer_ = buffer; + lfo_phase_[0] = 0.f; + lfo_phase_[1] = 0.f; + + lfo_freq_[0] = 0.f; + lfo_freq_[1] = 0.f; } - - template - inline void Interpolate( - D& d, float offset, LFOIndex index, float amplitude, float scale) { - STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); - offset += amplitude * lfo_value_[index]; - MAKE_INTEGRAL_FRACTIONAL(offset); - float a = DataType::Decompress( - buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); - float b = DataType::Decompress( - buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); - float x = a + (b - a) * offset_fractional; - previous_read_ = x; - accumulator_ += x * scale; + + void Clear() + { + std::fill(&buffer_[0], &buffer_[size], 0); + write_ptr_ = 0; } - - private: - float accumulator_; - float previous_read_; - float lfo_value_[2]; - T* buffer_; - int32_t write_ptr_; - DISALLOW_COPY_AND_ASSIGN(Context); - }; - - inline void SetLFOFrequency(LFOIndex index, float frequency) { - lfo_[index].template Init(frequency * 32.0f); - } - - inline void Start(Context* c) { - --write_ptr_; - if (write_ptr_ < 0) { - write_ptr_ += size; + struct Empty + { + }; + + template + struct Reserve + { + typedef T Tail; + enum + { + length = l + }; + }; + + template + struct DelayLine + { + enum + { + length = DelayLine::length, + base = DelayLine::base + + DelayLine::length + 1 + }; + }; + + template + struct DelayLine + { + enum + { + length = Memory::length, + base = 0 + }; + }; + + class Context + { + friend class FxEngine; + + public: + Context() {} + ~Context() {} + + inline void Load(float value) { accumulator_ = value; } + + inline void Read(float value, float scale) + { + accumulator_ += value * scale; + } + + inline void Read(float value) { accumulator_ += value; } + + inline void Write(float& value) { value = accumulator_; } + + inline void Write(float& value, float scale) + { + value = accumulator_; + accumulator_ *= scale; + } + + template + inline void Write(D& d, int32_t offset, float scale) + { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + T w = DataType::Compress(accumulator_); + if(offset == -1) + { + buffer_[(write_ptr_ + D::base + D::length - 1) & MASK] = w; + } + else + { + buffer_[(write_ptr_ + D::base + offset) & MASK] = w; + } + accumulator_ *= scale; + } + + template + inline void Write(D& d, float scale) + { + Write(d, 0, scale); + } + + template + inline void WriteAllPass(D& d, int32_t offset, float scale) + { + Write(d, offset, scale); + accumulator_ += previous_read_; + } + + template + inline void WriteAllPass(D& d, float scale) + { + WriteAllPass(d, 0, scale); + } + + template + inline void Read(D& d, int32_t offset, float scale) + { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + T r; + if(offset == -1) + { + r = buffer_[(write_ptr_ + D::base + D::length - 1) & MASK]; + } + else + { + r = buffer_[(write_ptr_ + D::base + offset) & MASK]; + } + float r_f = DataType::Decompress(r); + previous_read_ = r_f; + accumulator_ += r_f * scale; + } + + template + inline void Read(D& d, float scale) + { + Read(d, 0, scale); + } + + inline void Lp(float& state, float coefficient) + { + state += coefficient * (accumulator_ - state); + accumulator_ = state; + } + + inline void Hp(float& state, float coefficient) + { + state += coefficient * (accumulator_ - state); + accumulator_ -= state; + } + + template + inline void Interpolate(D& d, float offset, float scale) + { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + + int32_t offset_integral = static_cast(offset); + float offset_fractional + = offset - static_cast(offset_integral); + + float a = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); + float b = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); + float x = a + (b - a) * offset_fractional; + previous_read_ = x; + accumulator_ += x * scale; + } + + template + inline void Interpolate(D& d, + float offset, + LFOIndex index, + float amplitude, + float scale) + { + STATIC_ASSERT(D::base + D::length <= size, delay_memory_full); + lfo_phase_[index] += lfo_freq_[index]; + lfo_phase_[index] = lfo_phase_[index] >= 1.f + ? lfo_phase_[index] - 1.f + : lfo_phase_[index]; + + offset += amplitude * cosf(lfo_phase_[index] * TWOPI_F); + + int32_t offset_integral = static_cast(offset); + float offset_fractional + = offset - static_cast(offset_integral); + + float a = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base) & MASK]); + float b = DataType::Decompress( + buffer_[(write_ptr_ + offset_integral + D::base + 1) & MASK]); + float x = a + (b - a) * offset_fractional; + previous_read_ = x; + accumulator_ += x * scale; + } + + private: + float accumulator_; + float previous_read_; + float lfo_value_[2]; + T* buffer_; + int32_t write_ptr_; + + float lfo_phase_[2]; + float lfo_freq_[2]; + }; + + inline void SetLFOFrequency(LFOIndex index, float frequency) + { + lfo_freq_[index] = frequency; //* 32.f ? } - c->accumulator_ = 0.0f; - c->previous_read_ = 0.0f; - c->buffer_ = buffer_; - c->write_ptr_ = write_ptr_; - if ((write_ptr_ & 31) == 0) { - c->lfo_value_[0] = lfo_[0].Next(); - c->lfo_value_[1] = lfo_[1].Next(); - } else { - c->lfo_value_[0] = lfo_[0].value(); - c->lfo_value_[1] = lfo_[1].value(); + + inline void Start(Context* c) + { + --write_ptr_; + if(write_ptr_ < 0) + { + write_ptr_ += size; + } + c->accumulator_ = 0.0f; + c->previous_read_ = 0.0f; + c->buffer_ = buffer_; + c->write_ptr_ = write_ptr_; + + c->lfo_phase_[0] = lfo_phase_[0]; + c->lfo_phase_[1] = lfo_phase_[1]; + c->lfo_freq_[0] = lfo_freq_[0]; + c->lfo_freq_[1] = lfo_freq_[1]; + + if((write_ptr_ & 31) == 0) + { + lfo_phase_[0] += lfo_freq_[0]; + lfo_phase_[0] + = lfo_phase_[0] >= 1.f ? lfo_phase_[0] - 1.f : lfo_phase_[0]; + + lfo_phase_[1] += lfo_freq_[1]; + lfo_phase_[1] + = lfo_phase_[1] >= 1.f ? lfo_phase_[1] - 1.f : lfo_phase_[1]; + + c->lfo_value_[0] = cosf(TWOPI_F * lfo_phase_[0]); + c->lfo_value_[1] = cosf(TWOPI_F * lfo_phase_[1]); + } + else + { + c->lfo_value_[0] = cosf(TWOPI_F * lfo_phase_[0]); + c->lfo_value_[1] = cosf(TWOPI_F * lfo_phase_[1]); + } } - } - - private: - enum { - MASK = size - 1 - }; - - int32_t write_ptr_; - T* buffer_; - stmlib::CosineOscillator lfo_[2]; - - DISALLOW_COPY_AND_ASSIGN(FxEngine); -}; -} // namespace plaits + private: + enum + { + MASK = size - 1 + }; -#endif // PLAITS_DSP_FX_FX_ENGINE_H_ \ No newline at end of file + int32_t write_ptr_; + T* buffer_; + float lfo_phase_[2]; + float lfo_freq_[2]; +}; +} // namespace daisysp +#endif +#endif \ No newline at end of file From 5afab4a5fd33e0031194299e7f2568f7332e2465 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 14:15:45 -0500 Subject: [PATCH 06/11] sample based --- modules/diffuser.cpp | 49 ++++++++++++++++++++++---------------------- modules/diffuser.h | 2 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index 5758edb6..efe15891 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -11,7 +11,7 @@ void Diffuser::Init(uint16_t* buffer) lp_decay_ = 0.0f; } -void Diffuser::Process(float amount, float rt, float* in_out, size_t size) +float Diffuser::Process(float amount, float rt, float in) { typedef E::Reserve< 126, @@ -34,29 +34,28 @@ void Diffuser::Process(float amount, float rt, float* in_out, size_t size) const float kap = 0.625f; const float klp = 0.75f; float lp = lp_decay_; - while(size--) - { - float wet; - engine_.Start(&c); - c.Read(*in_out); - c.Read(ap1 TAIL, kap); - c.WriteAllPass(ap1, -kap); - c.Read(ap2 TAIL, kap); - c.WriteAllPass(ap2, -kap); - c.Read(ap3 TAIL, kap); - c.WriteAllPass(ap3, -kap); - c.Interpolate(ap4, 400.0f, LFO_1, 43.0f, kap); - c.WriteAllPass(ap4, -kap); - c.Interpolate(del, 3070.0f, LFO_1, 340.0f, rt); - c.Lp(lp, klp); - c.Read(dapa TAIL, -kap); - c.WriteAllPass(dapa, kap); - c.Read(dapb TAIL, kap); - c.WriteAllPass(dapb, -kap); - c.Write(del, 2.0f); - c.Write(wet, 0.0f); - *in_out += amount * (wet - *in_out); - ++in_out; - } + + float wet; + engine_.Start(&c); + c.Read(in); + c.Read(ap1 TAIL, kap); + c.WriteAllPass(ap1, -kap); + c.Read(ap2 TAIL, kap); + c.WriteAllPass(ap2, -kap); + c.Read(ap3 TAIL, kap); + c.WriteAllPass(ap3, -kap); + c.Interpolate(ap4, 400.0f, LFO_1, 43.0f, kap); + c.WriteAllPass(ap4, -kap); + c.Interpolate(del, 3070.0f, LFO_1, 340.0f, rt); + c.Lp(lp, klp); + c.Read(dapa TAIL, -kap); + c.WriteAllPass(dapa, kap); + c.Read(dapb TAIL, kap); + c.WriteAllPass(dapb, -kap); + c.Write(del, 2.0f); + c.Write(wet, 0.0f); + lp_decay_ = lp; + + return amount * (wet - in); } diff --git a/modules/diffuser.h b/modules/diffuser.h index 9ab8c179..2ae80af5 100644 --- a/modules/diffuser.h +++ b/modules/diffuser.h @@ -29,7 +29,7 @@ class Diffuser void Clear() { engine_.Clear(); } - void Process(float amount, float rt, float* in_out, size_t size); + float Process(float amount, float rt, float in); private: typedef FxEngine<8192, FORMAT_12_BIT> E; From 2a1d52daa506f91cb5b07689e8b88171f3aa5c57 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 14:25:15 -0500 Subject: [PATCH 07/11] pointer --- modules/fx_engine.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/fx_engine.h b/modules/fx_engine.h index 8e7b90d3..ed9df262 100644 --- a/modules/fx_engine.h +++ b/modules/fx_engine.h @@ -357,8 +357,8 @@ class FxEngine T* buffer_; int32_t write_ptr_; - float lfo_phase_[2]; - float lfo_freq_[2]; + float* lfo_phase_; + float* lfo_freq_; }; inline void SetLFOFrequency(LFOIndex index, float frequency) @@ -378,10 +378,8 @@ class FxEngine c->buffer_ = buffer_; c->write_ptr_ = write_ptr_; - c->lfo_phase_[0] = lfo_phase_[0]; - c->lfo_phase_[1] = lfo_phase_[1]; - c->lfo_freq_[0] = lfo_freq_[0]; - c->lfo_freq_[1] = lfo_freq_[1]; + c->lfo_phase_ = lfo_phase_; + c->lfo_freq_ = lfo_freq_; if((write_ptr_ & 31) == 0) { From affcfb0171528d7b725ca448e7731f36c26d50e6 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 14:58:07 -0500 Subject: [PATCH 08/11] fix clipping --- modules/diffuser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index efe15891..e8dba0b3 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -57,5 +57,5 @@ float Diffuser::Process(float amount, float rt, float in) lp_decay_ = lp; - return amount * (wet - in); + return .1f * amount * (wet - in); } From c47ea802356b712037465b196ae896652ae545c1 Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 15:01:43 -0500 Subject: [PATCH 09/11] local buffer --- modules/diffuser.cpp | 4 ++-- modules/diffuser.h | 5 ++++- modules/fx_engine.h | 37 +++++++++---------------------------- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index e8dba0b3..51af4790 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -4,9 +4,9 @@ using namespace daisysp; -void Diffuser::Init(uint16_t* buffer) +void Diffuser::Init() { - engine_.Init(buffer); + engine_.Init(buffer_); engine_.SetLFOFrequency(LFO_1, 0.3f / 48000.0f); lp_decay_ = 0.0f; } diff --git a/modules/diffuser.h b/modules/diffuser.h index 2ae80af5..5a522227 100644 --- a/modules/diffuser.h +++ b/modules/diffuser.h @@ -25,13 +25,16 @@ class Diffuser Diffuser() {} ~Diffuser() {} - void Init(uint16_t* buffer); + /** Initialize the module + */ + void Init(); void Clear() { engine_.Clear(); } float Process(float amount, float rt, float in); private: + uint16_t buffer_[8192]; typedef FxEngine<8192, FORMAT_12_BIT> E; E engine_; float lp_decay_; diff --git a/modules/fx_engine.h b/modules/fx_engine.h index ed9df262..e18c2a59 100644 --- a/modules/fx_engine.h +++ b/modules/fx_engine.h @@ -1,31 +1,3 @@ -// Copyright 2014 Emilie Gillet. -// -// Author: Emilie Gillet (emilie.o.gillet@gmail.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// See http://creativecommons.org/licenses/MIT/ for more information. -// -// ----------------------------------------------------------------------------- -// -// Base class for building reverbs. - #pragma once #ifndef DSY_FX_ENGINE_H #define DSY_FX_ENGINE_H @@ -46,6 +18,7 @@ message); \ }; +/** @file fx_engine.h */ namespace impl { template @@ -149,6 +122,14 @@ struct DataType static inline T Compress(float value) { return value; } }; +/** + @brief Base Class for building reverbs + @author Ben Sergentanis + @date Jan 2021 + Ported from pichenettes/eurorack/plaits/dsp/fx/fx_engine.h \n + to an independent module. \n + Original code written by Emilie Gillet in 2014. \n +*/ template class FxEngine { From f33a02d24eca057f75a414ee00a444f2cee1a8de Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 15:12:59 -0500 Subject: [PATCH 10/11] setters --- modules/diffuser.cpp | 8 ++++---- modules/diffuser.h | 22 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index 51af4790..c14f0ca7 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -11,7 +11,7 @@ void Diffuser::Init() lp_decay_ = 0.0f; } -float Diffuser::Process(float amount, float rt, float in) +float Diffuser::Process(float in) { typedef E::Reserve< 126, @@ -46,7 +46,7 @@ float Diffuser::Process(float amount, float rt, float in) c.WriteAllPass(ap3, -kap); c.Interpolate(ap4, 400.0f, LFO_1, 43.0f, kap); c.WriteAllPass(ap4, -kap); - c.Interpolate(del, 3070.0f, LFO_1, 340.0f, rt); + c.Interpolate(del, 3070.0f, LFO_1, 340.0f, rt_); c.Lp(lp, klp); c.Read(dapa TAIL, -kap); c.WriteAllPass(dapa, kap); @@ -57,5 +57,5 @@ float Diffuser::Process(float amount, float rt, float in) lp_decay_ = lp; - return .1f * amount * (wet - in); -} + return .1f * amount_ * (wet - in); +} \ No newline at end of file diff --git a/modules/diffuser.h b/modules/diffuser.h index 5a522227..66649869 100644 --- a/modules/diffuser.h +++ b/modules/diffuser.h @@ -25,16 +25,32 @@ class Diffuser Diffuser() {} ~Diffuser() {} - /** Initialize the module + /** Initialize the module */ void Init(); + /** Reset the reverb */ void Clear() { engine_.Clear(); } - float Process(float amount, float rt, float in); + /** Get the next sample + \param in Next sample to process + */ + float Process(float in); + + /** Set the reverb tail length + \param rt Works 0-1. + */ + void SetTime(float rt) { rt_ = fclamp(rt, 0.f, 1.f); } + + /** Set the amount of reverb. + \param amount Works 0-1. + */ + void SetAmount(float amount) { amount_ = fclamp(amount, 0.f, 1.f); }; private: - uint16_t buffer_[8192]; + float rt_, amount_; + + uint16_t buffer_[8192]; typedef FxEngine<8192, FORMAT_12_BIT> E; E engine_; float lp_decay_; From 77cdef29781e9f5c019609c06f4b08ca31df67ae Mon Sep 17 00:00:00 2001 From: "U-MSI\\Ben" Date: Fri, 15 Jan 2021 15:13:35 -0500 Subject: [PATCH 11/11] init --- modules/diffuser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/diffuser.cpp b/modules/diffuser.cpp index c14f0ca7..68335888 100644 --- a/modules/diffuser.cpp +++ b/modules/diffuser.cpp @@ -9,6 +9,9 @@ void Diffuser::Init() engine_.Init(buffer_); engine_.SetLFOFrequency(LFO_1, 0.3f / 48000.0f); lp_decay_ = 0.0f; + + SetAmount(1.f); + SetTime(.5f); } float Diffuser::Process(float in)