From bba034d726d1b71b489963e985e3c17b74f06d09 Mon Sep 17 00:00:00 2001 From: Connor Barker Date: Fri, 27 Dec 2024 17:08:54 -0500 Subject: [PATCH] move (#8) --- siderialib/include/effects/Disperse.h | 4 +- .../include/effects/delay/ModulatedDelay.h | 18 ---- .../effects/disperse/DisperseParallelVoice.h | 60 ++++++------- siderialib/src/effects/Disperse.cpp | 21 +++-- .../src/effects/delay/ModulatedDelay.cpp | 45 ---------- .../disperse/DisperseParallelVoice.cpp | 90 +++++++++++++++++++ .../src/effects/filter/BiquadFilter.cpp | 4 + spkr/spkr.cpp | 14 ++- 8 files changed, 146 insertions(+), 110 deletions(-) diff --git a/siderialib/include/effects/Disperse.h b/siderialib/include/effects/Disperse.h index ce7e5cc..7668922 100644 --- a/siderialib/include/effects/Disperse.h +++ b/siderialib/include/effects/Disperse.h @@ -49,8 +49,6 @@ namespace siderialib { sfloat _lastOutR = 0.f; LFO _lfo; - BiquadFilter _postLpfL; - BiquadFilter _postLpfR; void updateSpread(); void updateDispersionAndPosition(); @@ -95,6 +93,8 @@ namespace siderialib { inline sfloat getModDepth() const { return this->_modDepth; } void setMix(sfloat mix); inline sfloat getMix() const { return this->_mix; } + void setTone(sfloat tone); + inline sfloat getTone() const { return _tone; } void setPingPongType(DispersePingPong pingPong); diff --git a/siderialib/include/effects/delay/ModulatedDelay.h b/siderialib/include/effects/delay/ModulatedDelay.h index 512355f..df60353 100644 --- a/siderialib/include/effects/delay/ModulatedDelay.h +++ b/siderialib/include/effects/delay/ModulatedDelay.h @@ -24,20 +24,6 @@ namespace siderialib LFO *_mod; - // 2-stage lpf placed before writing to circular buffer, so in essence, filters delayed sounds many times - BiquadFilter _lpf1L; - BiquadFilter _lpf1R; - BiquadFilter _lpf2L; - BiquadFilter _lpf2R; - // 2-stage hpf - BiquadFilter _hpf1L; - BiquadFilter _hpf1R; - BiquadFilter _hpf2L; - BiquadFilter _hpf2R; - - bool _enableLpf; - bool _enableHpf; - bool _pingPong; PingPongDirection _pingPongDirection = PingPongDirection::LEFT; @@ -74,10 +60,6 @@ namespace siderialib void setPan(sfloat pan) { this->_pan = pan; } sfloat getPan() const { return this->_pan; } - void setLpfParams(sfloat cutoff, sfloat Q, sfloat dBGain); - void setHpfParams(sfloat cuoff, sfloat Q, sfloat dBGain); - void enableLpf(bool enabled) { this->_enableLpf = enabled; } - void enableHpf(bool enabled) { this->_enableHpf = enabled; } void enablePingPong(bool enabled) { this->_pingPong = enabled; } }; } \ No newline at end of file diff --git a/siderialib/include/effects/disperse/DisperseParallelVoice.h b/siderialib/include/effects/disperse/DisperseParallelVoice.h index 0c8b8c9..1dcf46e 100644 --- a/siderialib/include/effects/disperse/DisperseParallelVoice.h +++ b/siderialib/include/effects/disperse/DisperseParallelVoice.h @@ -1,7 +1,5 @@ #pragma once - -#include #include "effects/delay/ModulatedDelay.h" #include "DisperseConstants.h" @@ -15,48 +13,48 @@ namespace siderialib { sfloat _lastOutL = 0.0; sfloat _lastOutR = 0.0; - public: - DisperseParallelVoice() = default; - void addVoice(ModulatedDelay* delay) { - if (_numActiveVoices >= DISPERSE_NUM_VOICES) { - return; - } - _delays[_numActiveVoices] = delay; - _numActiveVoices++; - } + bool _enableTone = false; + // 2-stage lpf placed before writing to circular buffer, so in essence, filters delayed sounds many times + bool useLpf = false; + BiquadFilter _lpf1L; + BiquadFilter _lpf1R; + BiquadFilter _lpf2L; + BiquadFilter _lpf2R; - void clearVoices() { - for (int i = 0; i < _numActiveVoices; i++) { - _delays[i] = nullptr; - } + sfloat sampleRate = 0.0; - _numActiveVoices = 0; - } + bool useHpf = false; + // 2-stage hpf + BiquadFilter _hpf1L; + BiquadFilter _hpf1R; + BiquadFilter _hpf2L; + BiquadFilter _hpf2R; - void initialize() { - } + void applyFilters(); + public: + DisperseParallelVoice() = default; + + void addVoice(ModulatedDelay* delay); + + void clearVoices(); + + void initialize(sfloat samplingRate); - void tick(sfloat L, sfloat R) { - sfloat parallelL = L; - sfloat parallelR = R; + void tick(sfloat L, sfloat R); - for (int i = 0; i < _numActiveVoices; i++) { - _delays[i]->tick(L, R); - parallelL = _delays[i]->lastOutL(); - parallelR = _delays[i]->lastOutR(); - } + void setTone(sfloat tone); - _lastOutL = parallelL; - _lastOutR = parallelR; + void enableTone(bool enable) { + _enableTone = enable; } - sfloat lastOutL() const { + inline sfloat lastOutL() const { return _lastOutL; } - sfloat lastOutR() const { + inline sfloat lastOutR() const { return _lastOutR; } }; diff --git a/siderialib/src/effects/Disperse.cpp b/siderialib/src/effects/Disperse.cpp index 384ff51..db74989 100644 --- a/siderialib/src/effects/Disperse.cpp +++ b/siderialib/src/effects/Disperse.cpp @@ -74,6 +74,17 @@ void Disperse::setPingPongType(siderialib::DispersePingPong pingPong) { this->updatePingPong(); } +void Disperse::updateTone() { + for (int i = 0; i < DISPERSE_NUM_VOICES; i++) { + _voices[i].setTone(_tone); + } +} + +void Disperse::setTone(sfloat tone) { + this->_tone = tone; + updateTone(); +} + sfloat Disperse::lastOutR() const { return _lastOutR; } @@ -160,13 +171,12 @@ void Disperse::setResampleFactor(siderialib::sfloat ratio) { void Disperse::initialize(sfloat sampleRate) { this->_sampleRate = sampleRate; _lfo.initialize(sampleRate); - _postLpfL.initialize(_sampleRate, BiquadType::LPF, 8000.0, 0.7); - _postLpfR.initialize(_sampleRate, BiquadType::LPF, 8000.0, 0.7); int maxDelaySamps = std::ceil((DISPERSE_MAX_DELAY_MS/1000.0) * _sampleRate); for (int i = 0; i < DISPERSE_NUM_VOICES; i++) { _delays[i].initialize(&_lfo, _sampleRate, maxDelaySamps); - _delays[i].enableLpf(false); + _voices[i].initialize(_sampleRate); + _voices[i].enableTone(false); } setArrangement(DisperseArrangement::FULL_PARALLEL); @@ -193,12 +203,11 @@ void Disperse::initialize(sfloat *voiceBufs[DISPERSE_NUM_VOICES], sfloat sampleRate) { this->_sampleRate = sampleRate; _lfo.initialize(sampleRate); - _postLpfL.initialize(_sampleRate, BiquadType::LPF, 8000.0f, 0.7f); - _postLpfR.initialize(_sampleRate, BiquadType::LPF, 8000.0f, 0.7f); for (int i = 0; i < DISPERSE_NUM_VOICES; i++) { _delays[i].initialize(&_lfo, _sampleRate, voiceBufs[i], bufLength); - _delays[i].enableLpf(false); + _voices[i].initialize(_sampleRate); + _voices[i].enableTone(false); } setArrangement(DisperseArrangement::FULL_PARALLEL); diff --git a/siderialib/src/effects/delay/ModulatedDelay.cpp b/siderialib/src/effects/delay/ModulatedDelay.cpp index c595b4e..0e25b5e 100644 --- a/siderialib/src/effects/delay/ModulatedDelay.cpp +++ b/siderialib/src/effects/delay/ModulatedDelay.cpp @@ -34,18 +34,6 @@ void ModulatedDelay::tick(sfloat L, sfloat R) { } void ModulatedDelay::writeToBuffer(sfloat L, sfloat R) { - - if (_enableLpf) { - L = this->_lpf1L.tick(this->_lpf2L.tick(L)); - R = this->_lpf1R.tick(this->_lpf2R.tick(R)); - } - - if (_enableHpf) { - L = this->_hpf1L.tick(this->_hpf2L.tick(L)); - R = this->_hpf1R.tick(this->_hpf2R.tick(R)); - - } - this->_buf.writeCircular(L, R); } @@ -58,19 +46,6 @@ void ModulatedDelay::initialize(LFO *lfo, float sampleRate, int maxDelaySamps) { this->_mix = 1.0f; this->_mod = lfo; - - this->_enableLpf = false; - this->_enableHpf = false; - this->_lpf1L.initialize(_sampleRate, BiquadType::LPF, _sampleRate/2.f, 1.0); - this->_lpf1R.initialize(_sampleRate, BiquadType::LPF, _sampleRate/2.f, 1.0); - this->_lpf2L.initialize(_sampleRate, BiquadType::LPF, _sampleRate/2.f, 1.0); - this->_lpf2R.initialize(_sampleRate, BiquadType::LPF, _sampleRate/2.f, 1.0); - - this->_hpf1L.initialize(_sampleRate, BiquadType::HPF, _sampleRate/2.f, 1.0); - this->_hpf1R.initialize(_sampleRate, BiquadType::HPF, _sampleRate/2.f, 1.0); - this->_hpf2L.initialize(_sampleRate, BiquadType::HPF, _sampleRate/2.f, 1.0); - this->_hpf2R.initialize(_sampleRate, BiquadType::HPF, _sampleRate/2.f, 1.0); - } void ModulatedDelay::initialize(LFO *lfo, float sampleRate, sfloat *buf, int bufLength) { @@ -82,13 +57,6 @@ void ModulatedDelay::initialize(LFO *lfo, float sampleRate, sfloat *buf, int buf this->_mix = 1.0f; this->_mod = lfo; - - this->_enableLpf = false; - this->_lpf1L.initialize(sampleRate, BiquadType::LPF, sampleRate/2.f, 1.0); - this->_lpf1R.initialize(sampleRate, BiquadType::LPF, sampleRate/2.f, 1.0); - this->_lpf2L.initialize(sampleRate, BiquadType::LPF, sampleRate/2.f, 1.0); - this->_lpf2R.initialize(sampleRate, BiquadType::LPF, sampleRate/2.f, 1.0); - } sfloat ModulatedDelay::lastOutL() const { @@ -99,16 +67,3 @@ sfloat ModulatedDelay::lastOutR() const { return _lastOutR; } -void ModulatedDelay::setLpfParams(sfloat cutoff, sfloat Q, sfloat dBGain) { - this->_lpf1L.setParams(cutoff, Q, dBGain); - this->_lpf1R.setParams(cutoff, Q, dBGain); - this->_lpf2L.setParams(cutoff, Q, dBGain); - this->_lpf2R.setParams(cutoff, Q, dBGain); -} - -void ModulatedDelay::setHpfParams(sfloat cutoff, sfloat Q, sfloat dBGain) { - this->_hpf1L.setParams(cutoff, Q, dBGain); - this->_hpf1R.setParams(cutoff, Q, dBGain); - this->_hpf2L.setParams(cutoff, Q, dBGain); - this->_hpf2R.setParams(cutoff, Q, dBGain); -} diff --git a/siderialib/src/effects/disperse/DisperseParallelVoice.cpp b/siderialib/src/effects/disperse/DisperseParallelVoice.cpp index a3eb7ea..19bb482 100644 --- a/siderialib/src/effects/disperse/DisperseParallelVoice.cpp +++ b/siderialib/src/effects/disperse/DisperseParallelVoice.cpp @@ -1 +1,91 @@ #include "effects/disperse/DisperseParallelVoice.h" + +using namespace siderialib; + +void DisperseParallelVoice::addVoice(siderialib::ModulatedDelay *delay) { + if (_numActiveVoices >= DISPERSE_NUM_VOICES) { + return; + } + + _delays[_numActiveVoices] = delay; + _numActiveVoices++; +} + +void DisperseParallelVoice::clearVoices() { + for (int i = 0; i < _numActiveVoices; i++) { + _delays[i] = nullptr; + } + + _numActiveVoices = 0; +} + +void DisperseParallelVoice::initialize(sfloat samplingRate) { + _lpf1L.initialize(samplingRate, BiquadType::LPF, samplingRate / 2.f, 1.0); + _lpf1R.initialize(samplingRate, BiquadType::LPF, samplingRate / 2.f, 1.0); + _lpf2L.initialize(samplingRate, BiquadType::LPF, samplingRate / 2.f, 1.0); + _lpf2R.initialize(samplingRate, BiquadType::LPF, samplingRate / 2.f, 1.0); + + _hpf1L.initialize(samplingRate, BiquadType::HPF, 0.0, 1.0); + _hpf1R.initialize(samplingRate, BiquadType::HPF, 0.0, 1.0); + _hpf2L.initialize(samplingRate, BiquadType::HPF, 0.0, 1.0); + _hpf2R.initialize(samplingRate, BiquadType::HPF, 0.0, 1.0); + + this->sampleRate = samplingRate; +} + + +void DisperseParallelVoice::tick(siderialib::sfloat L, siderialib::sfloat R) { + sfloat parallelL = L; + sfloat parallelR = R; + + for (int i = 0; i < _numActiveVoices; i++) { + _delays[i]->tick(L, R); + parallelL = _delays[i]->lastOutL(); + parallelR = _delays[i]->lastOutR(); + } + + _lastOutL = parallelL; + _lastOutR = parallelR; + + if (_enableTone) { + applyFilters(); + } +} + +void DisperseParallelVoice::applyFilters() { + if (useLpf) { + _lastOutL = _lpf1L.tick(_lastOutL); + _lastOutR = _lpf1R.tick(_lastOutR); + _lastOutL = _lpf2L.tick(_lastOutL); + _lastOutR = _lpf2R.tick(_lastOutR); + } + + if (useHpf) { + _lastOutL = _hpf1L.tick(_lastOutL); + _lastOutR = _hpf1R.tick(_lastOutR); + _lastOutL = _hpf2L.tick(_lastOutL); + _lastOutR = _hpf2R.tick(_lastOutR); + } +} + +void DisperseParallelVoice::setTone(siderialib::sfloat tone) { + if (tone > 0.5) { + useHpf = true; + useLpf = false; + + sfloat cutoff = (sampleRate / 2.f) * (tone - 0.5f) * 2.f; + _hpf1L.setCutoff(cutoff); + _hpf1R.setCutoff(cutoff); + _hpf2L.setCutoff(cutoff); + _hpf2R.setCutoff(cutoff); + } else { + useHpf = false; + useLpf = true; + + sfloat cutoff = (sampleRate / 2.f) * tone * 2.f; + _lpf1L.setCutoff(cutoff); + _lpf1R.setCutoff(cutoff); + _lpf2L.setCutoff(cutoff); + _lpf2R.setCutoff(cutoff); + } +} \ No newline at end of file diff --git a/siderialib/src/effects/filter/BiquadFilter.cpp b/siderialib/src/effects/filter/BiquadFilter.cpp index be18f6d..a07c2e3 100644 --- a/siderialib/src/effects/filter/BiquadFilter.cpp +++ b/siderialib/src/effects/filter/BiquadFilter.cpp @@ -5,6 +5,10 @@ using namespace siderialib; void BiquadFilter::recalcParams() { + + // todo: find some way to cache these values + // since we usually set the same cutoff and Q + // to multiple filters at once double thetac = TWOPI * _cutoffHz / (double)this->_samplingRate; double K = tan(thetac / 2.0); double W = K * K; diff --git a/spkr/spkr.cpp b/spkr/spkr.cpp index bf3bcc6..2ce7f66 100644 --- a/spkr/spkr.cpp +++ b/spkr/spkr.cpp @@ -17,9 +17,6 @@ void applyDelay(std::vector> in, std::vector> in, std::vector> siderialib::Disperse disperse; float sampleRate = 44100.f; - float mix = 1.0f; - float timeMs = 100.0f; - float dispersion = 0.2f; + float mix = .2f; + float timeMs = 300.0f; + float dispersion = 0.5f; float spread = 1.0f; float feedback = 0.8f; - float tone = 0.8f; + float tone = 0.1f; float modRateHz = 2.0f; float modDepth = 0.3f; float position = .323f; - float resampleFactor = 1.0; + float resampleFactor = .2; siderialib::DisperseArrangement arrangement = siderialib::DisperseArrangement::FULL_PARALLEL; disperse.initialize(sampleRate); @@ -62,6 +59,7 @@ void apply(std::vector> in, std::vector> disperse.setModDepth(modDepth); disperse.setPosition(position); disperse.setResampleFactor(resampleFactor); + disperse.setTone(tone); disperse.setPingPongType(siderialib::DispersePingPong::OFF);