output to both channels but still only mono

This commit is contained in:
Gordon JC Pearce 2025-08-18 01:34:42 +01:00
parent 6bde8378ed
commit d5394a1fe2
5 changed files with 18 additions and 29 deletions

View File

@ -94,7 +94,7 @@ void Assigner::noteOff(uint8_t note) {
memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1); memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1);
voiceTbl[NUM_VOICES - 1] = v; voiceTbl[NUM_VOICES - 1] = v;
noteTbl[v] |= 0x80; noteTbl[v] |= 0x80;
voices[v].stopNote(note, 48000); voices[v].stopNote();
} }

View File

@ -24,15 +24,15 @@
#include <cstdio> #include <cstdio>
Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, programs, or states Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, programs, or states
bufferSize = xbufferSize;
sampleRate = xsampleRate;
lpfIn = new float[bufferSize]; 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
sampleRate = xsampleRate;
// lfo values taken from a rough simulation
fastPhase = 0; fastPhase = 0;
slowPhase = 0; slowPhase = 0;
@ -40,6 +40,7 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr
postFilter1 = new SVF(); postFilter1 = new SVF();
postFilter2 = new SVF(); postFilter2 = new SVF();
// lfo values taken from a rough simulation
fastOmega = 6.283 * 6.8 / sampleRate; // approximate, can be adjusted fastOmega = 6.283 * 6.8 / sampleRate; // approximate, can be adjusted
slowOmega = 6.283 * 0.7 / sampleRate; // again approximate slowOmega = 6.283 * 0.7 / sampleRate; // again approximate
@ -51,18 +52,6 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr
preFilter->setCutoff(12600, 1.3, sampleRate); preFilter->setCutoff(12600, 1.3, sampleRate);
postFilter1->setCutoff(11653, 6.6, sampleRate); postFilter1->setCutoff(11653, 6.6, sampleRate);
postFilter2->setCutoff(5883, 1.1, sampleRate); postFilter2->setCutoff(5883, 1.1, sampleRate);
// calculate SVF params
// hardcoded values for now
// this is the pre-chorus filter based around TR2
// It's actually a Sallen-Key filter which is easy to realise in hardware
// however a State Variable Filter is far easier to realise in software
// simple is good, and using a little maths we can work out that for
// R55 = R56 = 22k, C54 = 1.5nF, C76 = 220pF then the filter is at
// 12.6kHz and a Q of about 1.3
//
// Here is the best writeup ever on SVFs
// https://kokkinizita.linuxaudio.org/papers/digsvfilt.pdf
} }
Chorus::~Chorus() { Chorus::~Chorus() {
@ -86,8 +75,6 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
// filter the input // filter the input
preFilter->runSVF(input, lpfIn, frames); preFilter->runSVF(input, lpfIn, frames);
//memcpy(lpfIn, input, sizeof(float) * frames);
for (uint32_t i = 0; i < frames; i++) { for (uint32_t i = 0; i < frames; i++) {
// run a step of LFO // run a step of LFO
fastPhase += fastOmega; fastPhase += fastOmega;
@ -147,6 +134,8 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) {
delayptr++; delayptr++;
delayptr &= 0x3ff; delayptr &= 0x3ff;
} }
postFilter1->runSVF(lpfOut1, lpfOut2, frames); postFilter1->runSVF(lpfOut1, lpfOut2, frames);
postFilter2->runSVF(lpfOut2, outputs[0], frames); postFilter2->runSVF(lpfOut2, outputs[0], frames);
memcpy (outputs[1], outputs[0], frames * sizeof(float)); // only mono output for now
} }

View File

@ -26,13 +26,13 @@
class Chorus { class Chorus {
public: public:
Chorus(uint32_t bufferSize, double sampleRate); Chorus(uint32_t xbufferSize, double xsampleRate);
~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; uint32_t bufferSize;
double sampleRate;
double fastPhase, fastOmega; double fastPhase, fastOmega;
double slowPhase, slowOmega; double slowPhase, slowOmega;
double fastLfo, slowLfo; double fastLfo, slowLfo;

View File

@ -94,25 +94,25 @@ void Voice::startNote(uint8_t key, double sampleRate) {
// start a new note // start a new note
// violin and viola filter params // violin and viola filter params
float fc = 88.4 * powf(2, 0.083334 * (key - 24)); float fc = 88.4 * powf(2, 0.083334 * (key - 24));
c34 = 1 - exp(-6.283 * fc / 48000.0); c34 = 1 - exp(-6.283 * fc / sampleRate);
c33 = 1 - exp(-6.283 * fc /2 / 48000.0); c33 = 1 - exp(-6.283 * fc /2 / sampleRate);
// violin register // violin register
fc = 4000 * powf(2, 0.06 * (key - 24)); fc = 4000 * powf(2, 0.06 * (key - 24));
c78 = 1 - exp(-6.283 * fc / 48000.0); c78 = 1 - exp(-6.283 * fc / sampleRate);
c107 = 1 - exp(-6.283 * 154.0 / 48000.0); c107 = 1 - exp(-6.283 * 154.0 / sampleRate);
// viola register // viola register
fc = 6000 * powf(2, 0.07 * (key - 24)); fc = 6000 * powf(2, 0.07 * (key - 24));
c22 = 1 - exp(-6.283 * fc / 48000.0); c22 = 1 - exp(-6.283 * fc / sampleRate);
c31 = 1 - exp(-6.283 * 54.0 / 48000.0); c31 = 1 - exp(-6.283 * 54.0 / sampleRate);
gate = 1; gate = 1;
vcatc = 0.0001; vcatc = 0.0001;
} }
void Voice::stopNote(uint8_t key, double sampleRate) { void Voice::stopNote() {
gate = 0; gate = 0;
vcatc = 0.000033; vcatc = 0.000033;
} }

View File

@ -30,7 +30,7 @@ class Voice {
public: public:
void startNote(uint8_t key, double sampleRate); void startNote(uint8_t key, double sampleRate);
void stopNote(uint8_t key, double sampleRate); void stopNote();
private: private:
uint8_t semi, oct; uint8_t semi, oct;