stereo chorus

This commit is contained in:
Gordon JC Pearce 2025-08-19 23:33:47 +01:00
parent 7b138536ef
commit 2ea0409fe7
4 changed files with 24 additions and 32 deletions

View File

@ -23,12 +23,11 @@
#include <cstdio> #include <cstdio>
Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, programs, or states extern double sampleRate;
extern uint32_t bufferSize;
bufferSize = xbufferSize; Chorus::Chorus() { // no parameters, programs, or states
sampleRate = xsampleRate;
lpfIn = new float[bufferSize];
lpfOut1 = new float[bufferSize]; lpfOut1 = new float[bufferSize];
lpfOut2 = new float[bufferSize]; lpfOut2 = new float[bufferSize];
ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate ram = new float[DELAYSIZE]; // probably needs to be calculated based on sample rate
@ -36,8 +35,10 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr
fastPhase = 0; fastPhase = 0;
slowPhase = 0; slowPhase = 0;
postFilter1 = new SVF(8000, 1.3); postFilter1l = new SVF(POSTCUTOFF, .546);
postFilter2 = new SVF(8000, 0.54); postFilter2l = new SVF(POSTCUTOFF, 1.324);
postFilter1r = new SVF(POSTCUTOFF, .546);
postFilter2r = new SVF(POSTCUTOFF, 1.324);
// lfo values taken from a rough simulation // lfo values taken from a rough simulation
fastOmega = 6.283 * 5.7 / sampleRate; // approximate, can be adjusted fastOmega = 6.283 * 5.7 / sampleRate; // approximate, can be adjusted
@ -45,18 +46,18 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr
// zero out the delay buffer // zero out the delay buffer
memset(ram, 0, sizeof(float) * DELAYSIZE); memset(ram, 0, sizeof(float) * DELAYSIZE);
memset(lpfIn, 0, sizeof(float) * bufferSize);
memset(lpfOut1, 0, sizeof(float) * bufferSize); memset(lpfOut1, 0, sizeof(float) * bufferSize);
memset(lpfOut2, 0, sizeof(float) * bufferSize); memset(lpfOut2, 0, sizeof(float) * bufferSize);
} }
Chorus::~Chorus() { Chorus::~Chorus() {
delete lpfIn;
delete lpfOut1; delete lpfOut1;
delete lpfOut2; delete lpfOut2;
delete ram; delete ram;
delete postFilter1; delete postFilter1l;
delete postFilter2; delete postFilter2l;
delete postFilter1r;
delete postFilter2r;
} }
void Chorus::run(const float *input, float **outputs, uint32_t frames) { void Chorus::run(const float *input, float **outputs, uint32_t frames) {
@ -76,15 +77,6 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
ram[delayptr] = input[i]; ram[delayptr] = input[i];
// lowpass filter
// now we need to calculate the delay
// I don't know how long the Solina's delay lines are so I'm guessing 2-4ms for now
// normalised mod depths, from a quick simulation of the LFO block:
// 0deg 0.203 slow 0.635 fast
// 120deg 0.248 slow 0.745 fast
// 240deg 0.252 slow 0.609 fast
#define BASE 0.05 #define BASE 0.05
#define AMT 0.00175 #define AMT 0.00175
@ -121,13 +113,15 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
s0 = ram[tap & 0x3ff]; s0 = ram[tap & 0x3ff];
out240 = ((s1 - s0) * frac) + s0; out240 = ((s1 - s0) * frac) + s0;
lpfOut1[i] = (out0 + out120 + out240) / 3; lpfOut1[i] = (out0 + (out120 * 0.66) + (out240 * 0.33));
lpfOut2[i] = (out0 + (out120 * 0.33) + (out240 * 0.66));
delayptr++; delayptr++;
delayptr &= 0x3ff; delayptr &= 0x3ff;
} }
postFilter1->runSVF(lpfOut1, lpfOut2, frames); postFilter1l->runSVF(lpfOut1, lpfOut1, frames);
postFilter2->runSVF(lpfOut2, outputs[0], frames); postFilter2l->runSVF(lpfOut1, outputs[0], frames);
memcpy (outputs[1], outputs[0], frames * sizeof(float)); // only mono output for now postFilter1r->runSVF(lpfOut2, lpfOut2, frames);
postFilter2r->runSVF(lpfOut2, outputs[1], frames);
} }

View File

@ -24,15 +24,15 @@
// total size of delay line buffer // total size of delay line buffer
#define DELAYSIZE 1028 #define DELAYSIZE 1028
#define POSTCUTOFF 10000
class Chorus { class Chorus {
public: public:
Chorus(uint32_t xbufferSize, double xsampleRate); Chorus();
~Chorus(); ~Chorus();
void run(const float *input, float **outputs, uint32_t frames); void run(const float *input, float **outputs, uint32_t frames);
double sampleRate;
private: private:
uint32_t bufferSize;
double fastPhase, fastOmega; double fastPhase, fastOmega;
double slowPhase, slowOmega; double slowPhase, slowOmega;
double fastLfo, slowLfo; double fastLfo, slowLfo;
@ -43,6 +43,6 @@ class Chorus {
float *lpfIn; float *lpfIn;
float *lpfOut1, *lpfOut2; float *lpfOut1, *lpfOut2;
SVF *preFilter, *postFilter1, *postFilter2; SVF *postFilter1l, *postFilter2l, *postFilter1r, *postFilter2r;
}; };
#endif #endif

View File

@ -31,9 +31,7 @@ extern uint32_t bufferSize;
// unit-local global // unit-local global
static float envTc[2]; static float envTc[2];
// Generator::Generator(uint32_t bufferSize, double xSampleRate) {
Generator::Generator() { Generator::Generator() {
// sampleRate = xSampleRate;
output = new float[bufferSize]; output = new float[bufferSize];
// create the phase increments for each semitone // create the phase increments for each semitone
for (uint8_t i = 0; i < 12; i++) { for (uint8_t i = 0; i < 12; i++) {

View File

@ -20,6 +20,7 @@
double sampleRate; double sampleRate;
uint32_t bufferSize; uint32_t bufferSize;
START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO
Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0) { Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0) {
@ -27,11 +28,10 @@ Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0) {
sampleRate = getSampleRate(); sampleRate = getSampleRate();
bufferSize = getBufferSize(); bufferSize = getBufferSize();
genny = new Generator(); genny = new Generator();
assigner = new Assigner(genny->voices); assigner = new Assigner(genny->voices);
chorus = new Chorus();
chorus = new Chorus(getBufferSize(), sampleRate);
} }
Sonnenlicht::~Sonnenlicht() { Sonnenlicht::~Sonnenlicht() {