From 2d6d813ae5b7639e19e9849d5f838b48cbf11974 Mon Sep 17 00:00:00 2001 From: stephenhensley Date: Wed, 24 Feb 2021 23:08:57 -0800 Subject: [PATCH 1/4] added freverb, and associated elements. --- CMakeLists.txt | 4 + Makefile | 3 + Source/Effects/Freeverb.cpp | 186 +++++++++++++++++++++++++++++++++++ Source/Effects/Freeverb.h | 189 ++++++++++++++++++++++++++++++++++++ Source/Effects/FvAllpass.h | 66 +++++++++++++ Source/Effects/FvComb.h | 78 +++++++++++++++ Source/Utility/dsp.h | 8 ++ Source/daisysp.h | 1 + 8 files changed, 535 insertions(+) create mode 100644 Source/Effects/Freeverb.cpp create mode 100644 Source/Effects/Freeverb.h create mode 100644 Source/Effects/FvAllpass.h create mode 100644 Source/Effects/FvComb.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e84b1434..3e381824 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ Source/Effects/chorus.cpp Source/Effects/decimator.cpp Source/Effects/flanger.cpp Source/Effects/fold.cpp +Source/Effects/Freeverb.cpp Source/Effects/overdrive.cpp Source/Effects/reverbsc.cpp Source/Effects/sampleratereducer.cpp @@ -79,6 +80,9 @@ Source/Effects/bitcrush.h Source/Effects/chorus.h Source/Effects/decimator.h Source/Effects/flanger.h +Source/Effects/Freeverb.h +Source/Effects/FvAllpass.h +Source/Effects/FvComb.h Source/Effects/fold.h Source/Effects/overdrive.h Source/Effects/reverbsc.h diff --git a/Makefile b/Makefile index 20df5cb9..e3122ab3 100644 --- a/Makefile +++ b/Makefile @@ -35,11 +35,14 @@ bitcrush \ chorus \ decimator \ flanger \ +Freeverb \ fold \ overdrive \ reverbsc \ sampleratereducer \ tremolo +#FvComb +#FvAllpass #pitchshifter FILTER_MOD_DIR = Filters diff --git a/Source/Effects/Freeverb.cpp b/Source/Effects/Freeverb.cpp new file mode 100644 index 00000000..3d1aa322 --- /dev/null +++ b/Source/Effects/Freeverb.cpp @@ -0,0 +1,186 @@ +#include "Freeverb.h" + + +using namespace daisysp; + +void Freeverb::Init() +{ + /** Init all the buffs */ + combL[0].Init(bufcombL1, kCombTuningL1); + combR[0].Init(bufcombR1, kCombTuningR1); + combL[1].Init(bufcombL2, kCombTuningL2); + combR[1].Init(bufcombR2, kCombTuningR2); + combL[2].Init(bufcombL3, kCombTuningL3); + combR[2].Init(bufcombR3, kCombTuningR3); + combL[3].Init(bufcombL4, kCombTuningL4); + combR[3].Init(bufcombR4, kCombTuningR4); + combL[4].Init(bufcombL5, kCombTuningL5); + combR[4].Init(bufcombR5, kCombTuningR5); + combL[5].Init(bufcombL6, kCombTuningL6); + combR[5].Init(bufcombR6, kCombTuningR6); + combL[6].Init(bufcombL7, kCombTuningL7); + combR[6].Init(bufcombR7, kCombTuningR7); + combL[7].Init(bufcombL8, kCombTuningL8); + combR[7].Init(bufcombR8, kCombTuningR8); + allpassL[0].Init(bufallpassL1, kAllpassTuningL1); + allpassR[0].Init(bufallpassR1, kAllpassTuningR1); + allpassL[1].Init(bufallpassL2, kAllpassTuningL2); + allpassR[1].Init(bufallpassR2, kAllpassTuningR2); + allpassL[2].Init(bufallpassL3, kAllpassTuningL3); + allpassR[2].Init(bufallpassR3, kAllpassTuningR3); + allpassL[3].Init(bufallpassL4, kAllpassTuningL4); + allpassR[3].Init(bufallpassR4, kAllpassTuningR4); + + // Set default values + allpassL[0].SetFeedback(0.5f); + allpassR[0].SetFeedback(0.5f); + allpassL[1].SetFeedback(0.5f); + allpassR[1].SetFeedback(0.5f); + allpassL[2].SetFeedback(0.5f); + allpassR[2].SetFeedback(0.5f); + allpassL[3].SetFeedback(0.5f); + allpassR[3].SetFeedback(0.5f); + SetWet(kInitialwet); + SetRoomSize(kInitialroom); + SetDry(kInitialdry); + SetDamp(kInitialdamp); + SetWidth(kInitialwidth); + SetMode(kInitialmode); + // Clear the buffers + Mute(); +} +void Freeverb::Mute() +{ + if(GetMode() >= kFreezeMode) + return; + for(int i = 0; i < kNumCombs; i++) + { + combL[i].Mute(); + combR[i].Mute(); + } + for(int i = 0; i < kNumAllpass; i++) + { + allpassL[i].Mute(); + allpassR[i].Mute(); + } +} +void Freeverb::Process(float *inl, float *inr, float *outl, float *outr) +{ + float ol, or, input; + + ol = or = 0.f; + input = (*inl + *inr) * gain_; + + // Parallel comb accumulation + for(int i = 0; i < kNumCombs; i++) + { + ol += combL[i].Process(input); + or += combR[i].Process(input); + } + // Series allpass + for(int i = 0; i < kNumAllpass; i++) + { + ol = allpassL[i].Process(ol); + or = allpassR[i].Process(or); + } + // Calc replacement + *outl = ol * wet1_ + or *wet2_ + *inl * dry_; + *outr = or *wet1_ + ol * wet2_ + *inr * dry_; +} +void Freeverb::ProcessBlockReplace(float *inl, + float *inr, + float *outl, + float *outr, + int size, + int skip) +{ + float ol, or, input; + while(size--) + { + ol = or = 0.f; + input = (*inl + *inr) * gain_; + + // Parallel comb accumulation + for(int i = 0; i < kNumCombs; i++) + { + ol += combL[i].Process(input); + or += combR[i].Process(input); + } + // Series allpass + for(int i = 0; i < kNumAllpass; i++) + { + ol = allpassL[i].Process(ol); + or = allpassR[i].Process(or); + } + // Calc replacement + *outl = ol * wet1_ + or *wet2_ + *inl * dry_; + *outr = or *wet1_ + ol * wet2_ + *inr * dry_; + // Increment buffers + *inl += skip; + *inr += skip; + *outl += skip; + *outr += skip; + } +} +void Freeverb::ProcessBlockMix(float *inl, + float *inr, + float *outl, + float *outr, + int size, + int skip) +{ + float ol, or, input; + while(size--) + { + ol = or = 0.f; + input = (*inl + *inr) * gain_; + + // Parallel comb accumulation + for(int i = 0; i < kNumCombs; i++) + { + ol += combL[i].Process(input); + or += combR[i].Process(input); + } + // Series allpass + for(int i = 0; i < kNumAllpass; i++) + { + ol = allpassL[i].Process(ol); + or = allpassR[i].Process(or); + } + // Calcmixin + *outl = ol * wet1_ + or *wet2_ + *inl * dry_; + *outr = or *wet1_ + ol * wet2_ + *inr * dry_; + // Increment buffers + *inl += skip; + *inr += skip; + *outl += skip; + *outr += skip; + } +} + +void Freeverb::Update() +{ + wet1_ = wet_ * (width_ / 2.f + 0.5f); + if(mode_ > kFreezeMode) + { + roomsize1_ = 1.f; + damp1_ = 0; + gain_ = kMuted; + } + else + { + roomsize1_ = roomsize_; + damp1_ = damp_; + gain_ = kFixedGain; + } + for(int i = 0; i < kNumCombs; i++) + { + combL[i].SetFeedback(roomsize1_); + combR[i].SetFeedback(roomsize1_); + } + for(int i = 0; i < kNumCombs; i++) + { + combL[i].SetDamp(damp1_); + combR[i].SetDamp(damp1_); + } +} diff --git a/Source/Effects/Freeverb.h b/Source/Effects/Freeverb.h new file mode 100644 index 00000000..8b6c3e38 --- /dev/null +++ b/Source/Effects/Freeverb.h @@ -0,0 +1,189 @@ +#pragma once +#ifndef DSY_FREEVERB_H +#define DSY_FREEVERB_H + +#include "FvAllpass.h" +#include "FvComb.h" + +namespace daisysp +{ +/** Tuning Specific settings -- should be configurable */ +/** Considering either making this a separate header or just a config struct that could be used as a template parameter */ + +const int kNumCombs = 8; +const int kNumAllpass = 4; +const float kMuted = 0; +const float kFixedGain = 0.015f; +const float kScaleWet = 3; +const float kScaleDry = 2; +const float kScaledamp = 0.4f; +const float kScaleroom = 0.28f; +const float kOffsetroom = 0.7f; +const float kInitialroom = 0.5f; +const float kInitialdamp = 0.5f; +const float kInitialwet = 1 / kScaleWet; +const float kInitialdry = 0; +const float kInitialwidth = 1; +const float kInitialmode = 0; +const float kFreezeMode = 0.5f; +const int kStereoSpread = 23; + +// These values assume 44.1KHz sample rate +// they will probably be OK for 48KHz sample rate +// but would need scaling for 96KHz (or other) sample rates. +// The values were obtained by listening tests. +const int kCombTuningL1 = 1116; +const int kCombTuningR1 = 1116 + kStereoSpread; +const int kCombTuningL2 = 1188; +const int kCombTuningR2 = 1188 + kStereoSpread; +const int kCombTuningL3 = 1277; +const int kCombTuningR3 = 1277 + kStereoSpread; +const int kCombTuningL4 = 1356; +const int kCombTuningR4 = 1356 + kStereoSpread; +const int kCombTuningL5 = 1422; +const int kCombTuningR5 = 1422 + kStereoSpread; +const int kCombTuningL6 = 1491; +const int kCombTuningR6 = 1491 + kStereoSpread; +const int kCombTuningL7 = 1557; +const int kCombTuningR7 = 1557 + kStereoSpread; +const int kCombTuningL8 = 1617; +const int kCombTuningR8 = 1617 + kStereoSpread; +const int kAllpassTuningL1 = 556; +const int kAllpassTuningR1 = 556 + kStereoSpread; +const int kAllpassTuningL2 = 441; +const int kAllpassTuningR2 = 441 + kStereoSpread; +const int kAllpassTuningL3 = 341; +const int kAllpassTuningR3 = 341 + kStereoSpread; +const int kAllpassTuningL4 = 225; +const int kAllpassTuningR4 = 225 + kStereoSpread; + + +/** Freeverb Implementation + * based on original C++ sources from Jezar at Dreampoint, June 2000 + * + */ +class Freeverb +{ + public: + Freeverb() {} + ~Freeverb() {} + /** Initialize the internal bits */ + void Init(); + + /** Clear all of the filters and stop the reverb. */ + void Mute(); + + /** Process a single sample replacing the output */ + void Process(float *inl, float *inr, float *outl, float *outr); + + /** Processes a block of audio, skip can be used if necessary. + The contents of *outN are replaced by the new signal */ + void ProcessBlockReplace(float *inl, + float *inr, + float *outl, + float *outr, + int size, + int skip = 1); + + /** Processes a block of audio, skip can be used if necessary. + The contents of *outN are mixed with by the new signal */ + void ProcessBlockMix(float *inl, + float *inr, + float *outl, + float *outr, + int size, + int skip = 1); + + void SetRoomSize(float val) + { + roomsize_ = (val * kScaleroom) + kOffsetroom; + Update(); + } + inline float GetRoomSize() + { + return (roomsize_ - kOffsetroom) / kScaleroom; + } + + void SetDamp(float val) + { + damp_ = val * kScaledamp; + Update(); + } + const inline float GetDamp() const { return damp_ / kScaledamp; } + + void SetWet(float val) + { + wet_ = val * kScaleWet; + Update(); + } + const inline float GetWet() const { return wet_ / kScaleWet; } + + void SetDry(float val) + { + dry_ = val * kScaleDry; + Update(); + } + const inline float GetDry() const { return dry_ / kScaleDry; } + + void SetWidth(float val) + { + width_ = val; + Update(); + } + + const inline float GetWidth() const { return width_; } + + void SetMode(float val) + { + mode_ = val; + Update(); + } + const inline float GetMode() const + { + return mode_ > kFreezeMode ? 1.f : 0.f; + } + + + private: + void Update(); + float gain_, roomsize_, roomsize1_; + float damp_, damp1_; + float wet_, wet1_, wet2_; + float dry_; + float width_, mode_; + + FvComb combL[kNumCombs], combR[kNumCombs]; + FvAllpass allpassL[kNumAllpass], allpassR[kNumAllpass]; + + /** Buffers for combs */ + float bufcombL1[kCombTuningL1]; + float bufcombR1[kCombTuningR1]; + float bufcombL2[kCombTuningL2]; + float bufcombR2[kCombTuningR2]; + float bufcombL3[kCombTuningL3]; + float bufcombR3[kCombTuningR3]; + float bufcombL4[kCombTuningL4]; + float bufcombR4[kCombTuningR4]; + float bufcombL5[kCombTuningL5]; + float bufcombR5[kCombTuningR5]; + float bufcombL6[kCombTuningL6]; + float bufcombR6[kCombTuningR6]; + float bufcombL7[kCombTuningL7]; + float bufcombR7[kCombTuningR7]; + float bufcombL8[kCombTuningL8]; + float bufcombR8[kCombTuningR8]; + + // Buffers for the allpasses + float bufallpassL1[kAllpassTuningL1]; + float bufallpassR1[kAllpassTuningR1]; + float bufallpassL2[kAllpassTuningL2]; + float bufallpassR2[kAllpassTuningR2]; + float bufallpassL3[kAllpassTuningL3]; + float bufallpassR3[kAllpassTuningR3]; + float bufallpassL4[kAllpassTuningL4]; + float bufallpassR4[kAllpassTuningR4]; +}; + +} // namespace daisysp + +#endif \ No newline at end of file diff --git a/Source/Effects/FvAllpass.h b/Source/Effects/FvAllpass.h new file mode 100644 index 00000000..30a35b0a --- /dev/null +++ b/Source/Effects/FvAllpass.h @@ -0,0 +1,66 @@ +#pragma once +#ifndef DSY_FV_ALLPASS_H +#define DSY_FV_ALLPASS_H +#include "Utility/dsp.h" + + +namespace daisysp +{ +/** Allpass utility block for Freeverb. + Consider merging with previous allpass or replace if functionally similar + */ +class FvAllpass +{ + public: + FvAllpass() {} + ~FvAllpass() {} + + void Init(float *buf, size_t size) + { + buffer_ = buf; + size_ = size; + idx_ = 0; + Mute(); + fb_ = 0.7f; + } + + inline float Process(float input) + { + float output, bufout; + output = 0.f; + bufout = buffer_[idx_]; + denormalize(bufout); + output = -input + bufout; + buffer_[idx_] = input + (bufout * fb_); + idx_ += 1; + if(idx_ >= size_) + idx_ = 0; + return output; + } + + /** Clears internal buffer */ + void Mute() + { + for(int i = 0; i < size_; i++) + { + buffer_[i] = 0.f; + } + } + + /*** Sets the amount of feedback through the allpass */ + void SetFeedback(float val) { fb_ = val; } + + /** Returns the current feedback value. */ + const inline float GetFeedback() const { return fb_; } + + + private: + float fb_; + float *buffer_; + int size_, idx_; +}; + +} // namespace daisysp + + +#endif diff --git a/Source/Effects/FvComb.h b/Source/Effects/FvComb.h new file mode 100644 index 00000000..d6df9023 --- /dev/null +++ b/Source/Effects/FvComb.h @@ -0,0 +1,78 @@ +#pragma once +#ifndef DSY_FV_COMB_H +#define DSY_FV_COMB_H +#include "Utility/dsp.h" + + +namespace daisysp +{ +/** Comb utility block for Freeverb. + Consider merging with previous comb or replace if functionally similar + Lowpass Feedback Comb Filter + */ +class FvComb +{ + public: + FvComb() {} + ~FvComb() {} + + void Init(float *buf, int size) + { + buffer_ = buf; + size_ = size; + Mute(); + idx_ = 0; + fb_ = 0.5f; + prev_ = 0.f; + damp1_ = 0.3f; + damp2_ = 0.7f; + } + + void Mute() + { + for(int i = 0; i < size_; i++) + { + buffer_[i] = 0.f; + } + } + + inline float Process(float input) + { + float output; + output = buffer_[idx_]; + denormalize(output); + prev_ = (output * damp2_) + (prev_ * damp1_); + denormalize(prev_); + buffer_[idx_] = input + (prev_ * fb_); + idx_ += 1; + if(idx_ >= size_) + idx_ = 0; + return output; + } + + /*** Sets the amount of feedback through the allpass */ + void SetFeedback(float val) { fb_ = val; } + + /** Returns the current feedback value. */ + const inline float GetFeedback() const { return fb_; } + + /*** Sets the amount of feedback through the allpass */ + void SetDamp(float val) + { + damp1_ = val; + damp2_ = 1.f - val; + } + + /** Returns the current feedback value. */ + const inline float GetDamp() const { return damp1_; } + + private: + float fb_, prev_, damp1_, damp2_; + float *buffer_; + int size_, idx_; +}; + +} // namespace daisysp + + +#endif diff --git a/Source/Utility/dsp.h b/Source/Utility/dsp.h index fb5b9dcd..47213628 100644 --- a/Source/Utility/dsp.h +++ b/Source/Utility/dsp.h @@ -121,6 +121,14 @@ inline float mtof(float m) return powf(2, (m - 69.0f) / 12.0f) * 440.0f; } +/** Denormalize small floats in place + * Based on undernormalize macro by Jezar based on IS_DENORMAL macro by Jon Watte + */ +inline void denormalize(float &sample) +{ + if(((*(unsigned int *)&sample) & 0x7f800000) == 0) + sample = 0.f; +} /** one pole lpf out is passed by reference, and must be retained between diff --git a/Source/daisysp.h b/Source/daisysp.h index 7dec0e1d..61ef80eb 100644 --- a/Source/daisysp.h +++ b/Source/daisysp.h @@ -40,6 +40,7 @@ #include "Effects/chorus.h" #include "Effects/decimator.h" #include "Effects/flanger.h" +#include "Effects/Freeverb.h" #include "Effects/fold.h" #include "Effects/overdrive.h" #include "Effects/reverbsc.h" From 4cb5778994b5dccb5302645428b55d47be236515 Mon Sep 17 00:00:00 2001 From: stephenhensley Date: Wed, 24 Feb 2021 23:20:59 -0800 Subject: [PATCH 2/4] fixed misuse of or keyword with longer variable names. --- Source/Effects/Freeverb.cpp | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Source/Effects/Freeverb.cpp b/Source/Effects/Freeverb.cpp index 3d1aa322..669c88bd 100644 --- a/Source/Effects/Freeverb.cpp +++ b/Source/Effects/Freeverb.cpp @@ -66,26 +66,26 @@ void Freeverb::Mute() } void Freeverb::Process(float *inl, float *inr, float *outl, float *outr) { - float ol, or, input; + float left, right, input; - ol = or = 0.f; + left = right = 0.f; input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) { - ol += combL[i].Process(input); - or += combR[i].Process(input); + left += combL[i].Process(input); + right += combR[i].Process(input); } // Series allpass for(int i = 0; i < kNumAllpass; i++) { - ol = allpassL[i].Process(ol); - or = allpassR[i].Process(or); + left = allpassL[i].Process(left); + right = allpassR[i].Process(right); } // Calc replacement - *outl = ol * wet1_ + or *wet2_ + *inl * dry_; - *outr = or *wet1_ + ol * wet2_ + *inr * dry_; + *outl = left * wet1_ + right *wet2_ + *inl * dry_; + *outr = right *wet1_ + left * wet2_ + *inr * dry_; } void Freeverb::ProcessBlockReplace(float *inl, float *inr, @@ -94,27 +94,27 @@ void Freeverb::ProcessBlockReplace(float *inl, int size, int skip) { - float ol, or, input; + float left, right, input; while(size--) { - ol = or = 0.f; + left = right = 0.f; input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) { - ol += combL[i].Process(input); - or += combR[i].Process(input); + left += combL[i].Process(input); + right += combR[i].Process(input); } // Series allpass for(int i = 0; i < kNumAllpass; i++) { - ol = allpassL[i].Process(ol); - or = allpassR[i].Process(or); + left = allpassL[i].Process(left); + right = allpassR[i].Process(right); } // Calc replacement - *outl = ol * wet1_ + or *wet2_ + *inl * dry_; - *outr = or *wet1_ + ol * wet2_ + *inr * dry_; + *outl = left * wet1_ + right *wet2_ + *inl * dry_; + *outr = right *wet1_ + left * wet2_ + *inr * dry_; // Increment buffers *inl += skip; *inr += skip; @@ -129,27 +129,27 @@ void Freeverb::ProcessBlockMix(float *inl, int size, int skip) { - float ol, or, input; + float left, right, input; while(size--) { - ol = or = 0.f; + left = right = 0.f; input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) { - ol += combL[i].Process(input); - or += combR[i].Process(input); + left += combL[i].Process(input); + right += combR[i].Process(input); } // Series allpass for(int i = 0; i < kNumAllpass; i++) { - ol = allpassL[i].Process(ol); - or = allpassR[i].Process(or); + left = allpassL[i].Process(left); + right = allpassR[i].Process(right); } // Calcmixin - *outl = ol * wet1_ + or *wet2_ + *inl * dry_; - *outr = or *wet1_ + ol * wet2_ + *inr * dry_; + *outl = left * wet1_ + right *wet2_ + *inl * dry_; + *outr = right *wet1_ + left * wet2_ + *inr * dry_; // Increment buffers *inl += skip; *inr += skip; From d2671fd221a8a1b485fac3fa846efdc7e7e11963 Mon Sep 17 00:00:00 2001 From: stephenhensley Date: Wed, 24 Feb 2021 23:23:28 -0800 Subject: [PATCH 3/4] style fix --- Source/Effects/Freeverb.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Effects/Freeverb.cpp b/Source/Effects/Freeverb.cpp index 669c88bd..53ba4ccb 100644 --- a/Source/Effects/Freeverb.cpp +++ b/Source/Effects/Freeverb.cpp @@ -69,7 +69,7 @@ void Freeverb::Process(float *inl, float *inr, float *outl, float *outr) float left, right, input; left = right = 0.f; - input = (*inl + *inr) * gain_; + input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) @@ -80,12 +80,12 @@ void Freeverb::Process(float *inl, float *inr, float *outl, float *outr) // Series allpass for(int i = 0; i < kNumAllpass; i++) { - left = allpassL[i].Process(left); + left = allpassL[i].Process(left); right = allpassR[i].Process(right); } // Calc replacement - *outl = left * wet1_ + right *wet2_ + *inl * dry_; - *outr = right *wet1_ + left * wet2_ + *inr * dry_; + *outl = left * wet1_ + right * wet2_ + *inl * dry_; + *outr = right * wet1_ + left * wet2_ + *inr * dry_; } void Freeverb::ProcessBlockReplace(float *inl, float *inr, @@ -98,7 +98,7 @@ void Freeverb::ProcessBlockReplace(float *inl, while(size--) { left = right = 0.f; - input = (*inl + *inr) * gain_; + input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) @@ -109,12 +109,12 @@ void Freeverb::ProcessBlockReplace(float *inl, // Series allpass for(int i = 0; i < kNumAllpass; i++) { - left = allpassL[i].Process(left); + left = allpassL[i].Process(left); right = allpassR[i].Process(right); } // Calc replacement - *outl = left * wet1_ + right *wet2_ + *inl * dry_; - *outr = right *wet1_ + left * wet2_ + *inr * dry_; + *outl = left * wet1_ + right * wet2_ + *inl * dry_; + *outr = right * wet1_ + left * wet2_ + *inr * dry_; // Increment buffers *inl += skip; *inr += skip; @@ -133,7 +133,7 @@ void Freeverb::ProcessBlockMix(float *inl, while(size--) { left = right = 0.f; - input = (*inl + *inr) * gain_; + input = (*inl + *inr) * gain_; // Parallel comb accumulation for(int i = 0; i < kNumCombs; i++) @@ -144,12 +144,12 @@ void Freeverb::ProcessBlockMix(float *inl, // Series allpass for(int i = 0; i < kNumAllpass; i++) { - left = allpassL[i].Process(left); + left = allpassL[i].Process(left); right = allpassR[i].Process(right); } // Calcmixin - *outl = left * wet1_ + right *wet2_ + *inl * dry_; - *outr = right *wet1_ + left * wet2_ + *inr * dry_; + *outl = left * wet1_ + right * wet2_ + *inl * dry_; + *outr = right * wet1_ + left * wet2_ + *inr * dry_; // Increment buffers *inl += skip; *inr += skip; From 3c57f48ce77a961fb2b7a32663396cd96d558624 Mon Sep 17 00:00:00 2001 From: stephenhensley Date: Fri, 9 Jul 2021 14:33:16 -0700 Subject: [PATCH 4/4] added samplerate rescaling (still compile time). --- Source/Effects/Freeverb.h | 69 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/Source/Effects/Freeverb.h b/Source/Effects/Freeverb.h index 8b6c3e38..03c653ee 100644 --- a/Source/Effects/Freeverb.h +++ b/Source/Effects/Freeverb.h @@ -10,11 +10,12 @@ namespace daisysp /** Tuning Specific settings -- should be configurable */ /** Considering either making this a separate header or just a config struct that could be used as a template parameter */ -const int kNumCombs = 8; -const int kNumAllpass = 4; -const float kMuted = 0; -const float kFixedGain = 0.015f; -const float kScaleWet = 3; +const int kNumCombs = 8; +const int kNumAllpass = 4; +const float kMuted = 0; +const float kFixedGain = 0.015f; +//const float kScaleWet = 3; +const float kScaleWet = 4; const float kScaleDry = 2; const float kScaledamp = 0.4f; const float kScaleroom = 0.28f; @@ -28,35 +29,14 @@ const float kInitialmode = 0; const float kFreezeMode = 0.5f; const int kStereoSpread = 23; +constexpr float kTargetSr = 96000.f; +constexpr float kOriginalSr = 44100.f; +constexpr float kRetuneCoeff = (kTargetSr / kOriginalSr); + // These values assume 44.1KHz sample rate // they will probably be OK for 48KHz sample rate // but would need scaling for 96KHz (or other) sample rates. // The values were obtained by listening tests. -const int kCombTuningL1 = 1116; -const int kCombTuningR1 = 1116 + kStereoSpread; -const int kCombTuningL2 = 1188; -const int kCombTuningR2 = 1188 + kStereoSpread; -const int kCombTuningL3 = 1277; -const int kCombTuningR3 = 1277 + kStereoSpread; -const int kCombTuningL4 = 1356; -const int kCombTuningR4 = 1356 + kStereoSpread; -const int kCombTuningL5 = 1422; -const int kCombTuningR5 = 1422 + kStereoSpread; -const int kCombTuningL6 = 1491; -const int kCombTuningR6 = 1491 + kStereoSpread; -const int kCombTuningL7 = 1557; -const int kCombTuningR7 = 1557 + kStereoSpread; -const int kCombTuningL8 = 1617; -const int kCombTuningR8 = 1617 + kStereoSpread; -const int kAllpassTuningL1 = 556; -const int kAllpassTuningR1 = 556 + kStereoSpread; -const int kAllpassTuningL2 = 441; -const int kAllpassTuningR2 = 441 + kStereoSpread; -const int kAllpassTuningL3 = 341; -const int kAllpassTuningR3 = 341 + kStereoSpread; -const int kAllpassTuningL4 = 225; -const int kAllpassTuningR4 = 225 + kStereoSpread; - /** Freeverb Implementation * based on original C++ sources from Jezar at Dreampoint, June 2000 @@ -145,6 +125,35 @@ class Freeverb private: + static constexpr int kCombTuningL1 = 1116 * kRetuneCoeff; + static constexpr int kCombTuningR1 = (1116 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL2 = 1188 * kRetuneCoeff; + static constexpr int kCombTuningR2 = (1188 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL3 = 1277 * kRetuneCoeff; + static constexpr int kCombTuningR3 = (1277 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL4 = 1356 * kRetuneCoeff; + static constexpr int kCombTuningR4 = (1356 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL5 = 1422 * kRetuneCoeff; + static constexpr int kCombTuningR5 = (1422 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL6 = 1491 * kRetuneCoeff; + static constexpr int kCombTuningR6 = (1491 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL7 = 1557 * kRetuneCoeff; + static constexpr int kCombTuningR7 = (1557 + kStereoSpread) * kRetuneCoeff; + static constexpr int kCombTuningL8 = 1617 * kRetuneCoeff; + static constexpr int kCombTuningR8 = (1617 + kStereoSpread) * kRetuneCoeff; + static constexpr int kAllpassTuningL1 = 556 * kRetuneCoeff; + static constexpr int kAllpassTuningR1 + = (556 + kStereoSpread) * kRetuneCoeff; + static constexpr int kAllpassTuningL2 = 441 * kRetuneCoeff; + static constexpr int kAllpassTuningR2 + = (441 + kStereoSpread) * kRetuneCoeff; + static constexpr int kAllpassTuningL3 = 341 * kRetuneCoeff; + static constexpr int kAllpassTuningR3 + = (341 + kStereoSpread) * kRetuneCoeff; + static constexpr int kAllpassTuningL4 = 225 * kRetuneCoeff; + static constexpr int kAllpassTuningR4 + = (225 + kStereoSpread) * kRetuneCoeff; + void Update(); float gain_, roomsize_, roomsize1_; float damp_, damp1_;