diff --git a/plugin/ic29.cpp b/plugin/ic29.cpp index 26eb674..b7dfc13 100644 --- a/plugin/ic29.cpp +++ b/plugin/ic29.cpp @@ -30,7 +30,10 @@ Synth::Synth() { void Synth::buildTables(double sampleRate) { for (uint8_t i = 0; i < 104; i++) { - pitchTable[i] = 440.0f * powf(2, (i - 45) / 12.0f) / sampleRate; + // slightly flat middle C from ROM divider table + // actually adjusted a little so that the notes are bang on + // on the real synth the tuning knob is tweaked a little off to pull it in + pitchTable[i] = 260.15f * powf(2, (i - 36) / 12.0f) / sampleRate; } } @@ -39,25 +42,22 @@ void Synth::run() { // callled once every 4.3ms block of samples for (uint8_t i = 0; i < NUM_VOICES; i++) { - ic29.voices[i].env.run(); - ic29.voices[i].calcPitch(); + ic29.voices[i].update(); } } void Synth::voiceOn(uint8_t voice, uint8_t note) { // enable synth voice, start it all running voice &= 0x7f; - ic29.voices[voice].env.on(); - - // FIXME determine if we need to reset the counter - ic29.voices[voice].note = note; + ic29.voices[voice].on(note); } void Synth::voiceOff(uint8_t voice) { // enable synth voice, start it all running voice &= 0x7f; - ic29.voices[voice].env.off(); + ic29.voices[voice].off(); } + void Synth::basePitch() { uint16_t pitch = 0x1818; @@ -104,7 +104,7 @@ Voice::Voice() { } void Voice::calcPitch() { - uint16_t target = (note - 24) << 8; + uint16_t target = note << 8; if (ic29.portaCoeff != 0) { // porta up @@ -121,6 +121,14 @@ void Voice::calcPitch() { pitch = target; } + pitch += 0x1818; //ic29.masterPitch; + + if (pitch < 0x3000) pitch = 0x3000; // lowest note + if (pitch > 0x9700) pitch = 0x6700; // highest note + + pitch -= 0x3000; + //pitch &= 0xff00; + double o1 = ic29.pitchTable[pitch >> 8]; double o2 = ic29.pitchTable[(pitch >> 8) + 1]; double frac = (pitch & 0xff) / 255.0; @@ -128,6 +136,27 @@ void Voice::calcPitch() { omega = ((o2 - o1) * frac) + o1; } +void Voice::update() { + // calculate the once-per-block values + env.run(); + calcPitch(); + // do filter values +} + +void Voice::on(uint8_t key) { + voiceState = V_ON; + note = key; + env.on(); +} + +void Voice::off() { + // I need to rethink this bit FIXME + voiceState = V_OFF; + if (!ic29.sustained) { + env.off(); + } +} + void Voice::run(float *buffer, uint32_t samples) { float gain = env.level / 16384.0; gain *= 0.125; diff --git a/plugin/ic29.hpp b/plugin/ic29.hpp index 9b17dac..f39be0d 100644 --- a/plugin/ic29.hpp +++ b/plugin/ic29.hpp @@ -31,6 +31,11 @@ class Envelope { void off() { phase = ENV_RLS; } + + bool inRelease() { + return phase == ENV_RLS; + } + uint16_t level; // private: @@ -45,18 +50,21 @@ class Envelope { class Voice { public: Voice(); - void run(); - uint8_t note = 0x3c; // middle C + uint8_t note = 0x3c; // middle C + void run(float *buffer, uint32_t samples); + void update(); + void on(uint8_t note); + void off(); - // private: - Envelope env; // calculated envelope value + private: + Envelope env; // calculated envelope value uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc - float phase=0, omega=0; + float phase = 0, omega = 0; enum { V_DONE, V_OFF, V_ON } voiceState; - void calcPitch(); - void run(float *buffer, uint32_t samples); + + void calcPitch(); }; class Synth { @@ -75,13 +83,13 @@ class Synth { double sampleRate; uint16_t masterPitch; // sum of bend and LFO, plus any other pitch-setting value - // protected: + // protected: uint16_t envAtk, envDcy, envStn, envRls; - int16_t portaCoeff; + int8_t portaCoeff; + bool sustained; double pitchTable[104]; - - //private: + // private: int16_t lfoPitch; int16_t bendPitch; Voice voices[NUM_VOICES];