output to both channels but still only mono
This commit is contained in:
parent
6bde8378ed
commit
d5394a1fe2
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue