#pragma once #include "Lp1.h" #include "ModulatedDelay.h" #include "AllpassDiffuser.h" #include "Biquad.h" namespace ReverbHallRoom { template class CircularBuffer { float buffer[N]; int idxRead; int idxWrite; int count; public: CircularBuffer() { Reset(); } void Reset() { for (int i = 0; i < N; i++) buffer[i] = 0.0f; idxRead = 0; idxWrite = 0; count = 0; } int GetCount() { return count; } int PushZeros(float* data, int bufSize) { int countBefore = count; for (int i = 0; i < bufSize; i++) { buffer[idxWrite] = 0.0f; idxWrite = (idxWrite + 1) % N; count++; if (count >= N) break; // overflow } return count - countBefore; } int Push(float* data, int bufSize) { int countBefore = count; for (int i = 0; i < bufSize; i++) { buffer[idxWrite] = data[i]; idxWrite = (idxWrite + 1) % N; count++; if (count >= N) break; // overflow } return count - countBefore; } int Pop(float* destination, int bufSize) { int countBefore = count; for (int i = 0; i < bufSize; i++) { if (count > 0) { destination[i] = buffer[idxRead]; idxRead = (idxRead + 1) % N; count--; } else { destination[i] = 0.0f; } } return countBefore - count; } }; class DelayLine { private: ModulatedDelay delay; AllpassDiffuser diffuser; Biquad lowShelf; Biquad highShelf; Lp1 lowPass; CircularBuffer<2*BUFFER_SIZE> feedbackBuffer; float feedback; public: bool DiffuserEnabled; bool LowShelfEnabled; bool HighShelfEnabled; bool CutoffEnabled; bool TapPostDiffuser; DelayLine() : lowShelf(Biquad::FilterType::LowShelf, 48000), highShelf(Biquad::FilterType::HighShelf, 48000) { feedback = 0; lowShelf.SetGainDb(-20); lowShelf.Frequency = 20; highShelf.SetGainDb(-20); highShelf.Frequency = 19000; lowPass.SetCutoffHz(1000); lowShelf.Update(); highShelf.Update(); SetSamplerate(48000); SetDiffuserSeed(1, 0.0); } void SetSamplerate(int samplerate) { diffuser.SetSamplerate(samplerate); lowPass.SetSamplerate(samplerate); lowShelf.SetSamplerate(samplerate); highShelf.SetSamplerate(samplerate); } void SetDiffuserSeed(int seed, float crossSeed) { diffuser.SetSeed(seed); diffuser.SetCrossSeed(crossSeed); } void SetDelay(int delaySamples) { delay.SampleDelay = delaySamples; } void SetFeedback(float feedb) { feedback = feedb; } void SetDiffuserDelay(int delaySamples) { diffuser.SetDelay(delaySamples); } void SetDiffuserFeedback(float feedb) { diffuser.SetFeedback(feedb); } void SetDiffuserStages(int stages) { diffuser.Stages = stages; } void SetLowShelfGain(float gainDb) { lowShelf.SetGainDb(gainDb); lowShelf.Update(); } void SetLowShelfFrequency(float frequency) { lowShelf.Frequency = frequency; lowShelf.Update(); } void SetHighShelfGain(float gainDb) { highShelf.SetGainDb(gainDb); highShelf.Update(); } void SetHighShelfFrequency(float frequency) { highShelf.Frequency = frequency; highShelf.Update(); } void SetCutoffFrequency(float frequency) { lowPass.SetCutoffHz(frequency); } void SetLineModAmount(float amount) { delay.ModAmount = amount; } void SetLineModRate(float rate) { delay.ModRate = rate; } void SetDiffuserModAmount(float amount) { diffuser.SetModulationEnabled(amount > 0.0); diffuser.SetModAmount(amount); } void SetDiffuserModRate(float rate) { diffuser.SetModRate(rate); } void SetInterpolationEnabled(bool value) { diffuser.SetInterpolationEnabled(value); } void Process(float* input, float* output, int bufSize) { float tempBuffer[BUFFER_SIZE]; feedbackBuffer.Pop(tempBuffer, bufSize); for (int i = 0; i < bufSize; i++) tempBuffer[i] = input[i] + tempBuffer[i] * feedback; delay.Process(tempBuffer, tempBuffer, bufSize); if (!TapPostDiffuser) Utils::Copy(output, tempBuffer, bufSize); if (DiffuserEnabled) diffuser.Process(tempBuffer, tempBuffer, bufSize); if (LowShelfEnabled) lowShelf.Process(tempBuffer, tempBuffer, bufSize); if (HighShelfEnabled) highShelf.Process(tempBuffer, tempBuffer, bufSize); if (CutoffEnabled) lowPass.Process(tempBuffer, tempBuffer, bufSize); feedbackBuffer.Push(tempBuffer, bufSize); if (TapPostDiffuser) Utils::Copy(output, tempBuffer, bufSize); } void ClearDiffuserBuffer() { diffuser.ClearBuffers(); } void ClearBuffers() { delay.ClearBuffers(); diffuser.ClearBuffers(); lowShelf.ClearBuffers(); highShelf.ClearBuffers(); lowPass.Output = 0; feedbackBuffer.Reset(); } }; }