justasample/External/Gin/gin_simpleverb.cpp

328 lines
12 KiB
C++
Raw Normal View History

2026-07-23 23:40:48 +02:00
/*
==============================================================================
This file is part of the GIN library.
Copyright (c) 2019 - Roland Rabien.
==============================================================================
*/
#include "gin_simpleverb.h"
gin::SimpleVerb::SimpleVerb()
{
roomSizeFader = 0.5;
roomSize = 55;
preDelayFader = 0;
preDelayLength = 0;
preDelayPos = 0;
dampFader = 0.5;
damp = 0.25;
freqLPFader = 1;
freqHPFader = 0;
freqLP = 24000;
freqHP = 0;
b1LP = -std::exp(-2.0f * juce::MathConstants<float>::pi * freqLP / sampleRate); // 100Hz
a0LP = 1.0f + b1LP;
b1HP = -std::exp(-2.0f * juce::MathConstants<float>::pi * freqHP / sampleRate); // 100Hz
a0HP = 1.0f + b1HP;
dry = 1;
wet = 0.5;
setSampleRate(44100);
}
void gin::SimpleVerb::setSampleRate(float sr)
{
constexpr float roomMaxSize = 100.0f;
sampleRate = sr;
auto comb1MaxLength = static_cast<unsigned int>(C1 * roomMaxSize * sampleRate / 1000);
comb1.resize(comb1MaxLength);
auto comb2MaxLength = static_cast<unsigned int>(C2 * roomMaxSize * sampleRate / 1000);
comb2.resize(comb2MaxLength);
auto comb3MaxLength = static_cast<unsigned int>(C3 * roomMaxSize * sampleRate / 1000);
comb3.resize(comb3MaxLength);
auto comb4MaxLength = static_cast<unsigned int>(C4 * roomMaxSize * sampleRate / 1000);
comb4.resize(comb4MaxLength);
auto comb5MaxLength = static_cast<unsigned int>(C5 * roomMaxSize * sampleRate / 1000);
comb5.resize(comb5MaxLength);
auto comb6MaxLength = static_cast<unsigned int>(C6 * roomMaxSize * sampleRate / 1000);
comb6.resize(comb6MaxLength);
auto comb7MaxLength = static_cast<unsigned int>(C7 * roomMaxSize * sampleRate / 1000);
comb7.resize(comb7MaxLength);
auto comb8MaxLength = static_cast<unsigned int>(C8 * roomMaxSize * sampleRate / 1000);
comb8.resize(comb8MaxLength);
auto comb9MaxLength = static_cast<unsigned int>(C9 * roomMaxSize * sampleRate / 1000);
comb9.resize(comb9MaxLength);
auto comb10MaxLength = static_cast<unsigned int>(C10 * roomMaxSize * sampleRate / 1000);
comb10.resize(comb10MaxLength);
auto comb11MaxLength = static_cast<unsigned int>(C11 * roomMaxSize * sampleRate / 1000);
comb11.resize(comb11MaxLength);
auto comb12MaxLength = static_cast<unsigned int>(C12 * roomMaxSize * sampleRate / 1000);
comb12.resize(comb12MaxLength);
allpassL1Length = static_cast<unsigned int>(AL1 * sampleRate / 1000);
allpassL1.resize(allpassL1Length);
allpassL2Length = static_cast<unsigned int>((AL2 + SW) * sampleRate / 1000);
allpassL2.resize(allpassL2Length);
allpassL3Length = static_cast<unsigned int>(AL3 * sampleRate / 1000);
allpassL3.resize(allpassL3Length);
allpassR1Length = static_cast<unsigned int>((AR1 + SW) * sampleRate / 1000);
allpassR1.resize(allpassR1Length);
allpassR2Length = static_cast<unsigned int>(AR2 * sampleRate / 1000);
allpassR2.resize(allpassR2Length);
allpassR3Length = static_cast<unsigned int>((AR3 + SW) * sampleRate / 1000);
allpassR3.resize(allpassR3Length);
auto preDelayMaxLength = static_cast<unsigned int>(500 * sampleRate / 1000);
preDelay.resize(preDelayMaxLength);
flushPreDelay();
flushBuffers();
allpassL1Pos = allpassL2Pos = allpassL3Pos = allpassR1Pos = allpassR2Pos = allpassR3Pos = 0;
tmp1LP = tmp2LP = tmp1HP = tmp2HP = 0;
comb1Pos = comb2Pos = comb3Pos = comb4Pos = comb5Pos = comb6Pos = comb7Pos = comb8Pos = 0;
comb9Pos = comb10Pos = comb11Pos = comb12Pos = 0;
preDelayPos = 0;
}
void gin::SimpleVerb::flushPreDelay()
{
std::fill(preDelay.begin(), preDelay.end(), 0.0f);
}
void gin::SimpleVerb::flushBuffers()
{
std::fill(comb1.begin(), comb1.end(), 0.0f);
std::fill(comb2.begin(), comb2.end(), 0.0f);
std::fill(comb3.begin(), comb3.end(), 0.0f);
std::fill(comb4.begin(), comb4.end(), 0.0f);
std::fill(comb5.begin(), comb5.end(), 0.0f);
std::fill(comb6.begin(), comb6.end(), 0.0f);
std::fill(comb7.begin(), comb7.end(), 0.0f);
std::fill(comb8.begin(), comb8.end(), 0.0f);
std::fill(comb9.begin(), comb9.end(), 0.0f);
std::fill(comb10.begin(), comb10.end(), 0.0f);
std::fill(comb11.begin(), comb11.end(), 0.0f);
std::fill(comb12.begin(), comb12.end(), 0.0f);
std::fill(allpassL1.begin(), allpassL1.end(), 0.0f);
std::fill(allpassL2.begin(), allpassL2.end(), 0.0f);
std::fill(allpassL3.begin(), allpassL3.end(), 0.0f);
std::fill(allpassR1.begin(), allpassR1.end(), 0.0f);
std::fill(allpassR2.begin(), allpassR2.end(), 0.0f);
std::fill(allpassR3.begin(), allpassR3.end(), 0.0f);
}
void gin::SimpleVerb::setParameters(float roomIn, float dampIn, float preDelayIn, float lpFaderIn, float hpFaderIn, float wetIn, float dryIn)
{
if (!juce::approximatelyEqual(roomIn, roomSizeFader))
{
roomSizeFader = roomIn;
roomSize = 5 + roomSizeFader * roomSizeFader * 95;
comb1Length = static_cast<unsigned int>(C1 * roomSize * sampleRate / 1000);
comb1Pos = 0;
comb2Length = static_cast<unsigned int>(C2 * roomSize * sampleRate / 1000);
comb2Pos = 0;
comb3Length = static_cast<unsigned int>(C3 * roomSize * sampleRate / 1000);
comb3Pos = 0;
comb4Length = static_cast<unsigned int>(C4 * roomSize * sampleRate / 1000);
comb4Pos = 0;
comb5Length = static_cast<unsigned int>(C5 * roomSize * sampleRate / 1000);
comb5Pos = 0;
comb6Length = static_cast<unsigned int>(C6 * roomSize * sampleRate / 1000);
comb6Pos = 0;
comb7Length = static_cast<unsigned int>(C7 * roomSize * sampleRate / 1000);
comb7Pos = 0;
comb8Length = static_cast<unsigned int>(C8 * roomSize * sampleRate / 1000);
comb8Pos = 0;
comb9Length = static_cast<unsigned int>(C9 * roomSize * sampleRate / 1000);
comb9Pos = 0;
comb10Length = static_cast<unsigned int>(C10 * roomSize * sampleRate / 1000);
comb10Pos = 0;
comb11Length = static_cast<unsigned int>(C11 * roomSize * sampleRate / 1000);
comb11Pos = 0;
comb12Length = static_cast<unsigned int>(C12 * roomSize * sampleRate / 1000);
comb12Pos = 0;
flushBuffers();
}
if (!juce::approximatelyEqual(dampIn, dampFader))
{
dampFader = dampIn;
damp = std::min(1.0f - dampFader * dampFader, 0.95f);
}
if (!juce::approximatelyEqual(preDelayIn, preDelayFader))
{
preDelayFader = preDelayIn;
preDelayLength = static_cast<unsigned int>(preDelayFader * preDelayFader * 250 * sampleRate / 1000);
preDelayPos = 0;
flushPreDelay();
}
if (!juce::approximatelyEqual(lpFaderIn, freqLPFader))
{
freqLPFader = lpFaderIn;
freqLP = freqLPFader * freqLPFader * freqLPFader * 24000;
b1LP = -std::exp(-2.0f * juce::MathConstants<float>::pi * freqLP / sampleRate); // 100Hz
a0LP = 1.0f + b1LP;
}
if (!juce::approximatelyEqual(hpFaderIn, freqHPFader))
{
freqHPFader = hpFaderIn;
freqHP = freqHPFader * freqHPFader * freqHPFader * 24000;
b1HP = -std::exp(-2.0f * juce::MathConstants<float>::pi * freqHP / sampleRate); // 100Hz
a0HP = 1.0f + b1HP;
}
if (!juce::approximatelyEqual(dryIn, dryFader))
{
dryFader = dryIn;
dry = dryFader * 2;
}
if (!juce::approximatelyEqual(wetIn, wetFader))
{
wetFader = wetIn;
wet = wetFader * 2;
}
}
void gin::SimpleVerb::process(const float* in1, const float* in2, float* out1, float* out2, int numSamples)
{
int sampleFrames = numSamples;
while (--sampleFrames >= 0)
{
if (preDelayLength <= 1)
{
reverb = ((*in1) + (*in2)) / (1 + damp) + cDC_;
}
else
{
preDelay[preDelayPos] = ((*in1) + (*in2)) / (1 + damp) + cDC_;
if (++preDelayPos >= preDelayLength)
preDelayPos = 0;
reverb = preDelay[preDelayPos];
}
comb1[comb1Pos] = reverb * 0.49f + comb1[comb1Pos] * damp;
comb2[comb2Pos] = reverb * 0.76f + comb2[comb2Pos] * damp;
comb3[comb3Pos] = reverb * 1.00f + comb3[comb3Pos] * damp;
comb4[comb4Pos] = reverb * 0.91f + comb4[comb4Pos] * damp;
comb5[comb5Pos] = reverb * 0.79f + comb5[comb5Pos] * damp;
comb6[comb6Pos] = reverb * 0.71f + comb6[comb6Pos] * damp;
comb7[comb7Pos] = reverb * 0.59f + comb7[comb7Pos] * damp;
comb8[comb8Pos] = reverb * 0.51f + comb8[comb8Pos] * damp;
comb9[comb9Pos] = reverb * 0.42f + comb9[comb9Pos] * damp;
comb10[comb10Pos] = reverb * 0.38f + comb10[comb10Pos] * damp;
comb11[comb11Pos] = reverb * 0.35f + comb11[comb11Pos] * damp;
comb12[comb12Pos] = reverb * 0.30f + comb12[comb12Pos] * damp;
if (++comb1Pos >= comb1Length) comb1Pos = 0;
if (++comb2Pos >= comb2Length) comb2Pos = 0;
if (++comb3Pos >= comb3Length) comb3Pos = 0;
if (++comb4Pos >= comb4Length) comb4Pos = 0;
if (++comb5Pos >= comb5Length) comb5Pos = 0;
if (++comb6Pos >= comb6Length) comb6Pos = 0;
if (++comb7Pos >= comb7Length) comb7Pos = 0;
if (++comb8Pos >= comb8Length) comb8Pos = 0;
if (++comb9Pos >= comb9Length) comb9Pos = 0;
if (++comb10Pos >= comb10Length) comb10Pos = 0;
if (++comb11Pos >= comb11Length) comb11Pos = 0;
if (++comb12Pos >= comb12Length) comb12Pos = 0;
reverb = (comb1[comb1Pos]
+ comb2[comb2Pos]
+ comb3[comb3Pos]
+ comb4[comb4Pos]
+ comb5[comb5Pos]
+ comb6[comb6Pos]
+ comb7[comb7Pos]
+ comb8[comb8Pos]
+ comb9[comb9Pos]
+ comb10[comb10Pos]
+ comb11[comb11Pos]
+ comb12[comb12Pos]);
jassert(!std::isnan(reverb) && !std::isinf(reverb));
allpassL1[allpassL1Pos] = reverb + allpassL1[allpassL1Pos] * AP1FBQ;
left = (reverb - allpassL1[allpassL1Pos] * AP1FBQ);
jassert(!std::isnan(left) && !std::isinf(left));
if (++allpassL1Pos >= allpassL1Length)
allpassL1Pos = 0;
allpassL2[allpassL2Pos] = left + allpassL2[allpassL2Pos] * AP2FBQ;
left = (left - allpassL2[allpassL2Pos] * AP2FBQ);
jassert(!std::isnan(left) && !std::isinf(left));
if (++allpassL2Pos >= allpassL2Length)
allpassL2Pos = 0;
allpassL3[allpassL3Pos] = left + allpassL3[allpassL3Pos] * AP3FBQ;
left = (left - allpassL3[allpassL3Pos] * AP3FBQ);
jassert(!std::isnan(left) && !std::isinf(left));
if (++allpassL3Pos >= allpassL3Length)
allpassL3Pos = 0;
allpassR1[allpassR1Pos] = reverb + allpassR1[allpassR1Pos] * AP1FBQ;
right = (reverb - allpassR1[allpassR1Pos] * AP1FBQ);
jassert(!std::isnan(right) && !std::isinf(right));
if (++allpassR1Pos >= allpassR1Length)
allpassR1Pos = 0;
allpassR2[allpassR2Pos] = right + allpassR2[allpassR2Pos] * AP2FBQ;
right = (right - allpassR2[allpassR2Pos] * AP2FBQ);
jassert(!std::isnan(right) && !std::isinf(right));
if (++allpassR2Pos >= allpassR2Length)
allpassR2Pos = 0;
allpassR3[allpassR3Pos] = right + allpassR3[allpassR3Pos] * AP3FBQ;
right = (right - allpassR3[allpassR3Pos] * AP3FBQ);
jassert(!std::isnan(right) && !std::isinf(right));
if (++allpassR3Pos >= allpassR3Length)
allpassR3Pos = 0;
if (!juce::approximatelyEqual(freqHPFader, 0.0f))
{
left -= (tmp1HP = a0HP * left - b1HP * tmp1HP + cDC_) - cDC_;
right -= (tmp2HP = a0HP * right - b1HP * tmp2HP + cDC_) - cDC_;
jassert(!std::isnan(left) && !std::isinf(left));
jassert(!std::isnan(right) && !std::isinf(right));
}
if (!juce::approximatelyEqual(freqLPFader, 1.0f))
{
left = (tmp1LP = a0LP * left - b1LP * tmp1LP + cDC_) - cDC_;
right = (tmp2LP = a0LP * right - b1LP * tmp2LP + cDC_) - cDC_;
jassert(!std::isnan(left) && !std::isinf(left));
jassert(!std::isnan(right) && !std::isinf(right));
}
(*out1++) = (*in1++) * dry + left * wet;
(*out2++) = (*in2++) * dry + right * wet;
}
}