declick things, now just needs parameter tuning
This commit is contained in:
parent
132b684db7
commit
9d64247598
|
|
@ -29,6 +29,8 @@ Chorus::Chorus() {
|
|||
lfoPhase = 1;
|
||||
lfoSpeed = 6.283 * 10.7 / sampleRate; // plainly silly value to show if it hasn't been set
|
||||
|
||||
gainTC = 1 - exp(-6.283 * 10 / sampleRate);
|
||||
|
||||
// not quite Butterworth but you'd never hear the difference
|
||||
// these are calculated from the real-world component values
|
||||
postFilter1l = new SVF(9688, .549);
|
||||
|
|
@ -108,8 +110,10 @@ void Chorus::run(float* input, float** outputs, uint32_t frames) {
|
|||
|
||||
for (uint32_t i = 0; i < frames; i++) {
|
||||
float y = input[i];
|
||||
outputs[0][i] = y + (gain * lpfOut1[i]);
|
||||
outputs[1][i] = y + (gain * lpfOut2[i]);
|
||||
gainRC = (gain - gainRC) * gainTC + gainRC;
|
||||
|
||||
outputs[0][i] = y + (gainRC * lpfOut1[i]);
|
||||
outputs[1][i] = y + (gainRC * lpfOut2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,12 @@ class Chorus {
|
|||
private:
|
||||
double lfoPhase = 0, lfoSpeed = 0;
|
||||
uint8_t lfoState=0;
|
||||
|
||||
float gain = 1.2;
|
||||
|
||||
float gainRC = 0;
|
||||
float gainTC = 0;
|
||||
|
||||
|
||||
uint16_t delayptr = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,14 +18,29 @@
|
|||
|
||||
#include "module.hpp"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tables.hpp"
|
||||
|
||||
Module::Module() {
|
||||
// cutoff frequencies for various RC networks
|
||||
vcaTC = 1 - exp(-6.283 * 159 / sampleRate); // VCA and VCF 10k/0.1u time constant
|
||||
subTC = 1 - exp(-6.283 * 15 / sampleRate); // Main VCA and Sub Level 1k + 10u time constant
|
||||
pwmTC = 1 - exp(-6.283 * 40 / sampleRate); // integrator with 100k/0.047u time constant
|
||||
|
||||
vcaBuf = new float[bufferSize];
|
||||
subBuf = new float[bufferSize];
|
||||
pwmBuf = new float[bufferSize];
|
||||
}
|
||||
|
||||
void Module::run(Voice* voice) {
|
||||
Module::~Module() {
|
||||
printf("module destructor\n");
|
||||
delete vcaBuf;
|
||||
delete subBuf;
|
||||
delete pwmBuf;
|
||||
}
|
||||
void Module::run(Voice* voices, uint32_t blockSize) {
|
||||
// run updates for module board
|
||||
|
||||
// FIXME break these out to the patch setter
|
||||
|
|
@ -42,6 +57,7 @@ void Module::run(Voice* voice) {
|
|||
res = patchRam.vcfReso / 127.0 * 5;
|
||||
noise = patchRam.noise / 127.0;
|
||||
|
||||
// FIXME the exp in these is expensive, don't call it all the time
|
||||
chorus->setChorus(patchRam.switch1 & 0x60);
|
||||
chorus->setHpf(patchRam.switch2 & 0x18);
|
||||
|
||||
|
|
@ -50,9 +66,26 @@ void Module::run(Voice* voice) {
|
|||
else
|
||||
lfo = (lfoPhase & 0x3fff) - 0x1fff;
|
||||
|
||||
// FIXME represent PW as int until we calculate the block?
|
||||
pw = 0.5 - ((0x2000 + lfo) * patchRam.pwmLfo) / (32768.0f * 128);
|
||||
pw = (patchRam.switch2 & 0x01) ? 0.5 - (patchRam.pwmLfo / 256.0f) : pw;
|
||||
|
||||
float master = powf(2, (patchRam.vca / 31.75 - 4.0f));
|
||||
float sub = patchRam.sub/ 127.0f;
|
||||
|
||||
for (uint32_t i = 0; i < blockSize; i++) {
|
||||
vcaRC = (master - vcaRC) * subTC + vcaRC;
|
||||
pwmRC = (pw - pwmRC) * pwmTC + pwmRC;
|
||||
subRC = (sub - subRC) * vcaTC + subRC;
|
||||
|
||||
vcaBuf[i] = vcaRC;
|
||||
pwmBuf[i] = pwmRC;
|
||||
subBuf[i] = subRC;
|
||||
|
||||
|
||||
if (bufPtr < bufferSize) bufPtr++;
|
||||
}
|
||||
|
||||
int16_t vcf = (patchRam.vcfEnv << 7) * ((patchRam.switch2 & 0x02) ? -1 : 1);
|
||||
|
||||
int16_t pitchBase = 0x1818;
|
||||
|
|
@ -60,7 +93,7 @@ void Module::run(Voice* voice) {
|
|||
|
||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||
// maybe move all this into voice.cpp FIXME
|
||||
Voice* v = &voice[i];
|
||||
Voice* v = &voices[i];
|
||||
switch (v->envPhase) {
|
||||
case 0: // release phase FIXME use an enum I guess
|
||||
v->env = (v->env * r) >> 16; // "RC" decay to zero
|
||||
|
|
@ -78,6 +111,7 @@ void Module::run(Voice* voice) {
|
|||
}
|
||||
|
||||
// pitch
|
||||
// FIXME clean this all up a bit
|
||||
int16_t pitch = pitchBase + (v->note << 8);
|
||||
int16_t semi = pitch >> 8;
|
||||
float frac = (pitch & 0xff) / 256.0;
|
||||
|
|
@ -90,11 +124,12 @@ void Module::run(Voice* voice) {
|
|||
v->omega = px / (sampleRate * 4.0f); // fixme use proper scaler
|
||||
|
||||
// per voice we need to calculate the key follow amount and envelope amount
|
||||
v->vcfCut = (patchRam.vcfFreq << 7) + ((vcf * v->env) >> 16);
|
||||
v->vcfCut = (patchRam.vcfFreq << 7) + ((vcf * v->env) >> 14);
|
||||
v->vcfCut += (int)(v->note * (patchRam.vcfKey << 1) * 0.375);
|
||||
|
||||
if (v->vcfCut > 0x3fff) v->vcfCut = 0x3fff;
|
||||
if (v->vcfCut < 0) v->vcfCut = 0;
|
||||
|
||||
v->vcaEnv = (patchRam.switch2 & 0x04) ? (v->envPhase ? 0x3fff : 0) : v->env;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ class Voice;
|
|||
class Module {
|
||||
public:
|
||||
Module();
|
||||
~Module();
|
||||
|
||||
void run(Voice* voice);
|
||||
void run(Voice* voices, uint32_t blockLeft);
|
||||
|
||||
float res = 0;
|
||||
// precomputed values for all voices
|
||||
|
|
@ -45,6 +46,7 @@ class Module {
|
|||
|
||||
float saw = 0, square = 0, sub = 0, noise = 0;
|
||||
|
||||
|
||||
struct {
|
||||
uint8_t lfoRate = 0x18;
|
||||
uint8_t lfoDelay = 0x00;
|
||||
|
|
@ -67,7 +69,18 @@ class Module {
|
|||
} patchRam;
|
||||
Chorus* chorus;
|
||||
|
||||
float vcaTC;
|
||||
uint32_t bufPtr = 0;
|
||||
|
||||
float* vcaBuf;
|
||||
float* subBuf;
|
||||
float* pwmBuf;
|
||||
|
||||
private:
|
||||
// precalculated coefficients for RC networks
|
||||
float pwmTC = 0, subTC = 0, mVcaTC = 0;
|
||||
float pwmRC = 0, subRC = 0, vcaRC = 0;
|
||||
|
||||
// controls
|
||||
};
|
||||
|
||||
|
|
@ -81,9 +94,6 @@ class Voice {
|
|||
void run(Module* m, float* buffer, uint32_t samples);
|
||||
|
||||
private:
|
||||
// control
|
||||
float vcaRC = 0, vcfRC = 0;
|
||||
|
||||
float omega = 0, theta = 0; // phase increment and angle FIXME better names
|
||||
float delay = 0, lastpw = 0; // delay slots for antialiasing
|
||||
uint8_t pulseStage = 1; // pulse wave phase
|
||||
|
|
@ -93,7 +103,8 @@ class Voice {
|
|||
int16_t env = 0; // output amplitude
|
||||
int16_t vcfCut;
|
||||
int16_t vcaEnv;
|
||||
float vcaEnvRC = 0;
|
||||
float vcaRC = 0, vcfRC = 0;
|
||||
|
||||
uint8_t note = 0;
|
||||
|
||||
// filter
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ Peacock::Peacock() : Plugin(parameterCount, 0, 0) {
|
|||
ic1 = new Assigner;
|
||||
ic1->voice = voice;
|
||||
m->chorus = chorus;
|
||||
|
||||
|
||||
}
|
||||
|
||||
Peacock::~Peacock() {
|
||||
|
|
@ -73,6 +71,7 @@ void Peacock::run(const float**, float** outputs, uint32_t frames, const MidiEve
|
|||
|
||||
// if there were any events that happen between now and the end of this block, process them
|
||||
lastEvent = 0;
|
||||
m->bufPtr = 0;
|
||||
runMidi(midiEvents, midiEventCount, blockLeft);
|
||||
|
||||
while (framePos < frames) {
|
||||
|
|
@ -81,11 +80,12 @@ void Peacock::run(const float**, float** outputs, uint32_t frames, const MidiEve
|
|||
blockLeft = sampleRate / 238; // update rate in Hz
|
||||
runMidi(midiEvents, midiEventCount, framePos + blockLeft);
|
||||
|
||||
m->run(voice);
|
||||
}
|
||||
|
||||
// how many frames to do? Are we about to run off an update block
|
||||
sizeThisTime = (framesLeft < blockLeft) ? framesLeft : blockLeft;
|
||||
m->run(voice, sizeThisTime);
|
||||
|
||||
|
||||
// now run all the voices for this chunk of samples
|
||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||
|
|
@ -98,8 +98,8 @@ void Peacock::run(const float**, float** outputs, uint32_t frames, const MidiEve
|
|||
}
|
||||
|
||||
// now we've assembled a full chunk of audio
|
||||
//memcpy(outputs[0], m->vcaBuf, sizeof(float)* frames);
|
||||
chorus->run(outputs[0], outputs, frames);
|
||||
|
||||
}
|
||||
|
||||
Plugin* createPlugin() { return new Peacock(); }
|
||||
|
|
|
|||
|
|
@ -41,8 +41,10 @@ Voice::Voice() {
|
|||
|
||||
void Voice::on(uint8_t midiNote) {
|
||||
// omega = 261.63 * powf(2, (note - 60) / 12.0f) / 48000.0f;
|
||||
if (midiNote>24) note = midiNote-24;
|
||||
else note = 24;
|
||||
if (midiNote > 24)
|
||||
note = midiNote - 24;
|
||||
else
|
||||
note = 24;
|
||||
envPhase = 1;
|
||||
}
|
||||
|
||||
|
|
@ -54,8 +56,7 @@ void Voice::run(Module* m, float* buffer, uint32_t samples) {
|
|||
// carry out per-voice calculations for each block of samples
|
||||
float out, t, fb;
|
||||
|
||||
//float cut = 0.00513 + 0.0000075*env;
|
||||
|
||||
// FIXME incorrect
|
||||
// calculate cutoff frequency
|
||||
float cut = 248.0f * (powf(2, (vcfCut - 0x1880) / 1143.0f));
|
||||
cut = 0.25 * 6.2832 * cut / 48000.0f; // FIXME hardcoded values
|
||||
|
|
@ -71,8 +72,8 @@ void Voice::run(Module* m, float* buffer, uint32_t samples) {
|
|||
|
||||
while (true) {
|
||||
if (pulseStage == 0) {
|
||||
if (theta < m->pw) break;
|
||||
t = (theta - m->pw) / (lastpw - m->pw + omega);
|
||||
if (theta < m->pwmBuf[i]) break;
|
||||
t = (theta - m->pwmBuf[i]) / (lastpw - m->pwmBuf[i] + omega);
|
||||
out -= poly3blep0(t) * m->square;
|
||||
delay -= poly3blep1(t) * m->square;
|
||||
pulseStage = 1;
|
||||
|
|
@ -84,8 +85,8 @@ void Voice::run(Module* m, float* buffer, uint32_t samples) {
|
|||
out += poly3blep0(t) * (m->saw + m->square);
|
||||
delay += poly3blep1(t) * (m->saw + m->square);
|
||||
|
||||
out -= poly3blep0(t) * (m->sub * subosc);
|
||||
delay -= poly3blep1(t) * (m->sub * subosc);
|
||||
out -= poly3blep0(t) * (m->subBuf[i] * subosc);
|
||||
delay -= poly3blep1(t) * (m->subBuf[i] * subosc);
|
||||
pulseStage = 0;
|
||||
subosc = -subosc;
|
||||
|
||||
|
|
@ -93,14 +94,17 @@ void Voice::run(Module* m, float* buffer, uint32_t samples) {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME DC offset removal
|
||||
delay += m->saw * (1 - (2 * theta));
|
||||
delay += m->square * (pulseStage ? -1.f : 1.f);
|
||||
delay += m->sub * subosc;
|
||||
// delay += (1-(m->noisegen/(float)(1<<30))) * m->noise; FIXME figure out what to do about noise
|
||||
delay += m->square * ((pulseStage ? -1.f : 1.f) - m->pwmBuf[i] + 0.5);
|
||||
delay += m->subBuf[i] * subosc ;
|
||||
|
||||
out += m->noise * (0.8 - 1.6 * (rand() & 0xffff) / 65536.0);
|
||||
out *= 0.5;
|
||||
|
||||
// same time constant for both VCF and VCF RC circuits
|
||||
vcfRC = (cut - vcfRC) * m->vcaTC + vcfRC;
|
||||
|
||||
for (uint8_t ovs = 0; ovs < 4; ovs++) {
|
||||
fb = b4;
|
||||
// hard clip
|
||||
|
|
@ -110,16 +114,16 @@ void Voice::run(Module* m, float* buffer, uint32_t samples) {
|
|||
// fb = 1.5 * fb - 0.5 * fb * fb * fb;
|
||||
//
|
||||
|
||||
b1 = ((out + fb - b1) * cut) + b1;
|
||||
b2 = ((b1 - b2) * cut) + b2;
|
||||
b3 = ((b2 - b3) * cut) + b3;
|
||||
b4 = ((b3 - b4) * cut) + b4;
|
||||
b1 = ((out + fb - b1) * vcfRC) + b1;
|
||||
b2 = ((b1 - b2) * vcfRC) + b2;
|
||||
b3 = ((b2 - b3) * vcfRC) + b3;
|
||||
b4 = ((b3 - b4) * vcfRC) + b4;
|
||||
}
|
||||
|
||||
vcaEnvRC = (amp - vcaEnvRC) * 0.0203 + vcaEnvRC;
|
||||
vcaRC = (amp - vcaRC) * m->vcaTC + vcaRC;
|
||||
buffer[i] += 0.09367 * m->vcaBuf[i] * vcaRC * b4;
|
||||
|
||||
buffer[i] += 0.0367 * vcaEnvRC * b4;
|
||||
lastpw = m->pw;
|
||||
lastpw = m->pwmBuf[i];
|
||||
}
|
||||
// buffer[0] += 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue