sample rate stuff for chorus

This commit is contained in:
Gordon JC Pearce 2025-12-22 11:28:24 +00:00
parent 6f7f9340f1
commit 5ea59fb299
2 changed files with 39 additions and 37 deletions

View File

@ -21,24 +21,21 @@
#include <math.h>
#include <string.h>
#include <cstdio>
Chorus::Chorus() {
lpfOut1 = new float[bufferSize];
lpfOut2 = new float[bufferSize];
ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate
ram = new float[DELAYSIZE];
fastPhase = 0;
lfoPhase = 1;
lfoSpeed = 6.283 * 10.7 / sampleRate; // plainly silly value to show if it hasn't been set
// not quite Butterworth but you'd never hear the difference
// these are calculated from the real-world component values
postFilter1l = new SVF(9688, .549);
postFilter2l = new SVF(10377, 1.291);
postFilter1r = new SVF(9688, .549);
postFilter2r = new SVF(10377, 1.291);
// lfo values taken from a rough simulation
fastOmega = 6.283 * 0.7 / sampleRate; // approximate, can be adjusted
// zero out the delay buffer
memset(ram, 0, sizeof(float) * DELAYSIZE);
memset(lpfOut1, 0, sizeof(float) * bufferSize);
@ -56,32 +53,33 @@ Chorus::~Chorus() {
}
void Chorus::run(float* input, float** outputs, uint32_t frames) {
// actual effects here
// run highpass / bass boost and stereo chorus effect for one full block
// FIXME add highpass filter
// now run the DSP
float s0 = 0, s1 = 0;
float lfoMod, dly1, frac, flt;
uint16_t tap, delay;
for (uint32_t i = 0; i < frames; i++) {
// run a step of LFO
fastPhase += fastOmega;
if (fastPhase > 6.283) fastPhase -= 6.283;
lfoPhase += (lfoState & 0x01) ? lfoSpeed : -lfoSpeed;
flt = ((hpdelay - input[i]) * hpcut) + input[i];
hpdelay = flt;
input[i] += (flt * hpgain);
if (abs(lfoPhase) > 1) {
// lfoPhase -= 2;
lfoState++;
}
// highpass/bass boost
flt = ((input[i] - hpDelay) * hpCut) + hpDelay;
hpDelay = flt;
input[i] += (flt * hpGain);
ram[delayptr] = input[i];
// delays in milliseconds
#define BASE 0.005
#define AMT 0.00175
// FIXME make this triangle not sine, and move arithmetic out of mainloop
lfoMod = sin(fastPhase);
dly1 = (BASE + (AMT * lfoMod)) * sampleRate;
dly1 = (BASE + (AMT * lfoPhase)) * sampleRate;
delay = (int)dly1;
frac = dly1 - delay;
@ -90,7 +88,7 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) {
s0 = ram[tap & 0x3ff];
lpfOut1[i] = ((s1 - s0) * frac) + s0;
dly1 = (BASE - (AMT * lfoMod)) * sampleRate;
dly1 = (BASE - (AMT * lfoPhase)) * sampleRate;
delay = (int)dly1;
frac = dly1 - delay;
@ -99,9 +97,6 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) {
s0 = ram[tap & 0x3ff];
lpfOut2[i] = ((s1 - s0) * frac) + s0;
// lpfOut1[i] = input[i] + 1.2 * out0; //(out0 + (out120 * 0.66) + (out240 * 0.33));
// lpfOut2[i] = input[i] + 1.2 * out120; //(out0 + (out120 * 0.33) + (out240 * 0.66));
delayptr++;
delayptr &= 0x3ff;
}
@ -119,22 +114,27 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) {
}
void Chorus::setHpf(uint8_t mode) {
// the simple 1-pole lowpass has its output
// subtracted from input for the highpass
// or added for bass boost
// cutoff is calculated as
// k = 1-exp(-2pi * Fc * sampleRate)
switch (mode) {
case 0x00:
hpcut = 0.91245;
hpgain = -1;
hpCut = 1 - exp(-6.283 * 720 / sampleRate);
hpGain = -1;
break;
case 0x08:
hpcut = 0.97097;
hpgain = -1;
hpCut = 1 - exp(-6.283 * 225 / sampleRate);
hpGain = -1;
break;
case 0x10:
hpcut = 1;
hpgain = 0;
hpCut = 1;
hpGain = 0;
break;
case 0x18:
hpcut = 0.99088;
hpgain = 1;
hpCut = 1 - exp(-6.283 * 85 / sampleRate);
hpGain = 1.707;
break;
}
}
@ -147,11 +147,11 @@ void Chorus::setChorus(uint8_t mode) {
break;
case 0x40:
gain = 1.2;
fastOmega = 6.283 * 0.5 / sampleRate;
break; // approximate, can be adjusted
lfoSpeed = 6.283 * 0.5 / sampleRate;
break;
case 0x00:
gain = 1.2;
fastOmega = 6.283 * 0.9 / sampleRate;
break; // approximate, can be adjusted
lfoSpeed = 6.283 * 0.9 / sampleRate;
break;
}
}

View File

@ -38,16 +38,18 @@ class Chorus {
void setChorus(uint8_t mode);
private:
double fastPhase = 0, fastOmega = 0;
double lfoPhase = 0, lfoSpeed = 0;
uint8_t lfoState=0;
float gain = 1.2;
uint16_t delayptr = 0;
float* ram;
float* lpfIn;
float *lpfOut1, *lpfOut2;
float hpdelay=0, hpcut=0, hpgain=1;
float hpDelay=0, hpCut=0, hpGain=0;
SVF *postFilter1l, *postFilter2l, *postFilter1r, *postFilter2r;
};