stereo reverb

This commit is contained in:
Zack Buhman 2026-06-03 19:01:57 -05:00
parent 91a44e9c5e
commit 45e2867877
3 changed files with 56 additions and 39 deletions

View File

@ -8,8 +8,8 @@ namespace audio {
constexpr int channels = 2; constexpr int channels = 2;
struct DelayFilter { struct DelayFilter {
float * buffer; float * buffers[channels];
int index; int indexes[channels];
const int maxDelay; const int maxDelay;
int delay; int delay;
@ -18,23 +18,23 @@ namespace audio {
DelayFilter(int maxDelay, int delay, float gain); DelayFilter(int maxDelay, int delay, float gain);
void reset(); void reset();
virtual float feed(float value) = 0; virtual float feed(int channel, float value) = 0;
}; };
struct FeedbackCombFilter : DelayFilter { struct FeedbackCombFilter : DelayFilter {
FeedbackCombFilter(int maxDelay, int delay, float gain); FeedbackCombFilter(int maxDelay, int delay, float gain);
float feed(float value) override; float feed(int channel, float value) override;
}; };
struct FeedforwardCombFilter : DelayFilter { struct FeedforwardCombFilter : DelayFilter {
public: public:
FeedforwardCombFilter(int maxDelay, int delay, float gain); FeedforwardCombFilter(int maxDelay, int delay, float gain);
float feed(float value) override; float feed(int channel, float value) override;
}; };
struct AllpassFilter : DelayFilter { struct AllpassFilter : DelayFilter {
AllpassFilter(int maxDelay, int delay, float gain); AllpassFilter(int maxDelay, int delay, float gain);
float feed(float x) override; float feed(int channel, float x) override;
}; };
using FBCF = FeedbackCombFilter; using FBCF = FeedbackCombFilter;
@ -52,11 +52,11 @@ namespace audio {
Reverb(DelayFilter * cf, DelayFilter * ap); Reverb(DelayFilter * cf, DelayFilter * ap);
void reset(); void reset();
lr feed(float x); lr feed(int channel, float x);
}; };
extern int reverbIndex; extern int reverbIndex;
extern Reverb * reverbs[]; extern Reverb reverbs[];
extern int const reverbsCount; extern int const reverbsCount;
extern float wetGain; extern float wetGain;

View File

@ -34,16 +34,20 @@ namespace audio {
void DelayFilter::reset() void DelayFilter::reset()
{ {
memset(buffer, 0, maxDelay * (sizeof (float))); for (int i = 0; i < channels; i++) {
memset(buffers[i], 0, maxDelay * (sizeof (float)));
indexes[i] = 0;
}
} }
DelayFilter::DelayFilter(int maxDelay, int delay, float gain) DelayFilter::DelayFilter(int maxDelay, int delay, float gain)
: index(0) : maxDelay(maxDelay)
, maxDelay(maxDelay)
, delay(delay) , delay(delay)
, gain(gain) , gain(gain)
{ {
buffer = (float *)malloc(maxDelay * (sizeof (float))); for (int i = 0; i < channels; i++) {
buffers[i] = (float *)malloc(maxDelay * (sizeof (float)));
}
reset(); reset();
} }
@ -55,8 +59,11 @@ namespace audio {
: DelayFilter(maxDelay, delay, gain) : DelayFilter(maxDelay, delay, gain)
{} {}
float FeedbackCombFilter::feed(float value) float FeedbackCombFilter::feed(int channel, float value)
{ {
int & index = indexes[channel];
float * buffer = buffers[channel];
float y = gain * value + gain * buffer[index]; float y = gain * value + gain * buffer[index];
buffer[index] = y; buffer[index] = y;
index = (index + 1) % delay; index = (index + 1) % delay;
@ -71,8 +78,11 @@ namespace audio {
: DelayFilter(maxDelay, delay, gain) : DelayFilter(maxDelay, delay, gain)
{} {}
float FeedforwardCombFilter::feed(float value) float FeedforwardCombFilter::feed(int channel, float value)
{ {
int & index = indexes[channel];
float * buffer = buffers[channel];
float y = gain * value + gain * buffer[index]; float y = gain * value + gain * buffer[index];
buffer[index] = value; buffer[index] = value;
index = (index + 1) % delay; index = (index + 1) % delay;
@ -87,8 +97,11 @@ namespace audio {
: DelayFilter(maxDelay, delay, gain) : DelayFilter(maxDelay, delay, gain)
{} {}
float AllpassFilter::feed(float x) float AllpassFilter::feed(int channel, float x)
{ {
int & index = indexes[channel];
float * buffer = buffers[channel];
float v = x + -gain * buffer[index]; float v = x + -gain * buffer[index];
float y = buffer[index] + gain * v; float y = buffer[index] + gain * v;
buffer[index] = v; buffer[index] = v;
@ -108,16 +121,16 @@ namespace audio {
ap[i].reset(); ap[i].reset();
} }
lr Reverb::feed(float x) lr Reverb::feed(int channel, float x)
{ {
for (int i = 0; i < apCount; i++) { for (int i = 0; i < apCount; i++) {
x = ap[i].feed(x); x = ap[i].feed(channel, x);
} }
float x0 = cf[0].feed(x); float x0 = cf[0].feed(channel, x);
float x1 = cf[1].feed(x); float x1 = cf[1].feed(channel, x);
float x2 = cf[2].feed(x); float x2 = cf[2].feed(channel, x);
float x3 = cf[3].feed(x); float x3 = cf[3].feed(channel, x);
float s0 = x0 + x2; float s0 = x0 + x2;
float s1 = x1 + x3; float s1 = x1 + x3;
@ -139,7 +152,6 @@ namespace audio {
static AP forwardAP[3]{AP{2500, 2017, 0.7f}, static AP forwardAP[3]{AP{2500, 2017, 0.7f},
AP{2500, 647, 0.7f}, AP{2500, 647, 0.7f},
AP{2500, 137, 0.7f}}; AP{2500, 137, 0.7f}};
Reverb forwardReverb(forwardCF, forwardAP);
static FBCF backCF[4]{FBCF{10000, 3229, 0.733f}, // 1687 static FBCF backCF[4]{FBCF{10000, 3229, 0.733f}, // 1687
FBCF{10000, 3079, 0.802f}, // 1601 FBCF{10000, 3079, 0.802f}, // 1601
@ -148,12 +160,11 @@ namespace audio {
static AP backAP[3]{AP{1500, 661, 0.7f}, // 347 static AP backAP[3]{AP{1500, 661, 0.7f}, // 347
AP{1500, 257, 0.7f}, // 113 AP{1500, 257, 0.7f}, // 113
AP{1500, 71, 0.7f}}; AP{1500, 71, 0.7f}};
Reverb backReverb(backCF, backAP);
int reverbIndex = 0; int reverbIndex = 0;
Reverb * reverbs[] = { Reverb reverbs[] = {
&backReverb, {backCF, backAP},
&forwardReverb, {forwardCF, forwardAP},
}; };
int const reverbsCount = (sizeof (reverbs)) / (sizeof (reverbs[0])); int const reverbsCount = (sizeof (reverbs)) / (sizeof (reverbs[0]));
@ -198,7 +209,7 @@ namespace audio {
audio_instances_count = 0; audio_instances_count = 0;
for (int i = 0; i < reverbsCount; i++) for (int i = 0; i < reverbsCount; i++)
reverbs[i]->reset(); reverbs[i].reset();
for (int i = 0; i < mixChannelCount; i++) { for (int i = 0; i < mixChannelCount; i++) {
mixChannelGain[i] = 1.0f; mixChannelGain[i] = 1.0f;
@ -539,15 +550,21 @@ namespace audio {
// audio configuration "B" // audio configuration "B"
// mono reverberation // mono reverberation
for (int i = 0; i < half_period_samples; i++) { for (int i = 0; i < half_period_samples; i++) {
float value = channel_buffer[mix_channel::voice][i * channels + 0]; float mix[2] = { 0, 0 };
for (int ch = 0; ch < channels; ch++) {
float value = channel_buffer[mix_channel::voice][i * channels + ch];
lr wet; assert(reverbIndex >= 0 && reverbIndex < reverbsCount);
assert(reverbIndex >= 0 && reverbIndex < reverbsCount); lr wet = reverbs[reverbIndex].feed(ch, value);
wet = reverbs[reverbIndex]->feed(value);
float left = value * dryGain + wet.l * wetGain; float left = value * dryGain + wet.l * wetGain;
float right = value * dryGain + wet.r * wetGain; float right = value * dryGain + wet.r * wetGain;
channel_buffer[mix_channel::voice][i * channels + 0] = left; mix[0 ^ ch] += left;
channel_buffer[mix_channel::voice][i * channels + 1] = right; mix[1 ^ ch] += right;
}
for (int ch = 0; ch < channels; ch++)
channel_buffer[mix_channel::voice][i * channels + ch] = mix[ch];
} }
for (int i = 0; i < half_period_samples; i++) { for (int i = 0; i < half_period_samples; i++) {

View File

@ -74,15 +74,15 @@ namespace ui
reverberatorSliders[i].ap[j] = reverberatorSliders[i].ap[j] =
widget::DelayGainSlider(allpassLabels[j], widget::DelayGainSlider(allpassLabels[j],
allpassLeft, top + ySpace * j, allpassLeft, top + ySpace * j,
1, audio::reverbs[i]->ap[j].maxDelay, &audio::reverbs[i]->ap[j].delay, 1, audio::reverbs[i].ap[j].maxDelay, &audio::reverbs[i].ap[j].delay,
0.0, 1.0, &audio::reverbs[i]->ap[j].gain); 0.0, 1.0, &audio::reverbs[i].ap[j].gain);
} }
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
reverberatorSliders[i].comb[j] = reverberatorSliders[i].comb[j] =
widget::DelayGainSlider(combLabels[j], widget::DelayGainSlider(combLabels[j],
combLeft, top + ySpace * j, combLeft, top + ySpace * j,
100, audio::reverbs[i]->cf[j].maxDelay, &audio::reverbs[i]->cf[j].delay, 100, audio::reverbs[i].cf[j].maxDelay, &audio::reverbs[i].cf[j].delay,
0.0, 1.0, &audio::reverbs[i]->cf[j].gain); 0.0, 1.0, &audio::reverbs[i].cf[j].gain);
} }
} }
} }