diff --git a/plugin/chassis.cpp b/plugin/chassis.cpp index 81efd3e..09695d1 100644 --- a/plugin/chassis.cpp +++ b/plugin/chassis.cpp @@ -164,6 +164,18 @@ void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) { case 18: s.patch.sub = val / 127.0f; break; + case 73: + s.patch.attack = attack_table[val]; + break; + + case 75: + s.patch.decay = decay_table[val]; + break; + case 72: + s.patch.release = decay_table[val]; + break; + case 27: + s.patch.sustain = val << 7; } break; } @@ -196,7 +208,7 @@ void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEv // printf("compute params and reset block size\n"); for (uint32_t i = 0; i < NUM_VOICES; i++) { - s.voice[i].gate(); + s.voice[i].gate(s); } } diff --git a/plugin/chassis.hpp b/plugin/chassis.hpp index 870ed91..97c4e16 100644 --- a/plugin/chassis.hpp +++ b/plugin/chassis.hpp @@ -26,6 +26,9 @@ START_NAMESPACE_DISTRHO +//uint16_t attack_table[128]; +//uint16_t decay_table[128]; + class Chassis : public Plugin { public: enum Parameters { @@ -77,6 +80,46 @@ class Chassis : public Plugin { DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Chassis); }; + +uint16_t attack_table[128] = { + 0x4000, 0x2000, 0x1000, 0x0aaa, 0x0800, 0x0666, 0x0555, 0x0492, 0x0400, + 0x038e, 0x0333, 0x02e9, 0x02ab, 0x0276, 0x0249, 0x0222, 0x0200, 0x01e2, + 0x01c7, 0x01af, 0x0199, 0x0186, 0x0174, 0x0164, 0x0155, 0x0148, 0x013b, + 0x012f, 0x0124, 0x011a, 0x0111, 0x0108, 0x0100, 0x00f8, 0x00f1, 0x00ea, + 0x00e4, 0x00dd, 0x00d8, 0x00d2, 0x00cd, 0x00c8, 0x00c3, 0x00bf, 0x00ba, + 0x00b6, 0x00b2, 0x00ae, 0x00ab, 0x00a7, 0x00a4, 0x00a1, 0x009e, 0x009b, + 0x0098, 0x0095, 0x0092, 0x0090, 0x008d, 0x008b, 0x0089, 0x0086, 0x0084, + 0x0082, 0x007f, 0x007d, 0x007a, 0x0077, 0x0074, 0x0072, 0x006f, 0x006c, + 0x0069, 0x0067, 0x0064, 0x0061, 0x005e, 0x005c, 0x0059, 0x0056, 0x0053, + 0x0050, 0x004e, 0x004b, 0x0048, 0x0045, 0x0042, 0x0040, 0x003f, 0x003d, + 0x003c, 0x003a, 0x0039, 0x0037, 0x0036, 0x0034, 0x0033, 0x0031, 0x0030, + 0x002e, 0x002d, 0x002b, 0x002a, 0x0028, 0x0027, 0x0025, 0x0024, 0x0022, + 0x0021, 0x0021, 0x0020, 0x0020, 0x001f, 0x001f, 0x001e, 0x001e, 0x001d, + 0x001d, 0x001c, 0x001c, 0x001b, 0x001b, 0x001a, 0x0019, 0x0018, 0x0017, + 0x0016, 0x0015}; + +uint16_t decay_table[128] = { + 0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xa000, 0xa800, 0xb000, 0xb800, + 0xc000, 0xc800, 0xd000, 0xd800, 0xe000, 0xe800, 0xf000, 0xf080, 0xf100, + 0xf180, 0xf200, 0xf280, 0xf300, 0xf380, 0xf400, 0xf480, 0xf500, 0xf580, + 0xf600, 0xf680, 0xf700, 0xf780, 0xf800, 0xf880, 0xf900, 0xf980, 0xfa00, + 0xfa80, 0xfb00, 0xfb80, 0xfc00, 0xfc80, 0xfd00, 0xfd80, 0xfe00, 0xfe0c, + 0xfe18, 0xfe24, 0xfe30, 0xfe3c, 0xfe48, 0xfe54, 0xfe60, 0xfe6c, 0xfe78, + 0xfe84, 0xfe90, 0xfe9c, 0xfea8, 0xfeb4, 0xfec0, 0xfecc, 0xfed8, 0xfee4, + 0xfef0, 0xfefc, 0xff08, 0xff0c, 0xff10, 0xff14, 0xff18, 0xff1c, 0xff20, + 0xff24, 0xff28, 0xff2c, 0xff30, 0xff34, 0xff38, 0xff3c, 0xff40, 0xff44, + 0xff48, 0xff4c, 0xff50, 0xff54, 0xff58, 0xff5c, 0xff60, 0xff64, 0xff68, + 0xff6c, 0xff70, 0xff74, 0xff78, 0xff7c, 0xff80, 0xff84, 0xff88, 0xff8c, + 0xff90, 0xff94, 0xff98, 0xff9c, 0xffa0, 0xffa4, 0xffa8, 0xffac, 0xffb0, + 0xffb4, 0xffb8, 0xffbc, 0xffc0, 0xffc4, 0xffc8, 0xffcc, 0xffd0, 0xffd4, + 0xffd8, 0xffdc, 0xffe0, 0xffe4, 0xffe8, 0xffec, 0xfff0, 0xfff1, 0xfff2, + 0xfff3, 0xfff4}; + + + END_NAMESPACE_DISTRHO + + + #endif // _CHASSIS_HPP diff --git a/plugin/voice.cpp b/plugin/voice.cpp index aa6cd60..c537e4e 100644 --- a/plugin/voice.cpp +++ b/plugin/voice.cpp @@ -22,50 +22,112 @@ #include -static float blep(float p, float theta) { - float t; - - // low (late) side of step - if (p < theta) { - printf("phase < theta, %f %f\n", p, theta); - t = p / theta; - return (2 * t) - (t * t) - 1; - } - // high (early) side of step - if (p > (1 - theta)) { - printf("phase > 1-theta %f %f \n", p, theta); - t = (p - 1) / theta; - return (2 * t) + (t * t) + 1; - } - - // printf("no action\n"); - return 0; -} - bool Voice::isFree() { - return keyState == K_OFF; + return ff10 == false; } void Voice::on(uint32_t key, bool reset = 0) { - keyState = K_WAIT; - // envState = ATTACK; + + //printf("======================================================================================\n"); + ff10 = true; + + ff07 = true; + if (note == key) goto h0144; note = key; - if (reset) env = 0; - omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f; - target = 1; - env = 1; + if (ff11) goto h013e; + h0132: + if (ff33) goto h0149; + ff33 = false; + goto h0149; + + h013e: + ff00 = true; + goto h0149; + + h0144: + if (!ff11) goto h0132; + + h0149: + //printf("after 0144h, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33); + omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f; } void Voice::off() { - keyState = K_OFF; - envState = RELEASE; - target = 0; + bool sustain = false; + ff10 = false; + if (!sustain) { // dummy sustain + ff33 = false; + } + + //printf("after note off, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33); } -void Voice::gate() { - env = ((target - env) * 0.005f) + env; - if (env < 0.001) env = 0; - env = target; +void Voice::gate(Synth &s) { + + uint16_t bc, ea=env; + + ff11 = ff10; + + + + // 0509 + if (!ff11) goto h0538; + + // 050e + if (!ff33) goto h0563; + + // 0513 + if (!ff07) goto h051e; + + // 0517 + h0517: + //printf("got to 0517\n"); + ff07 = false; + + h051e: + + //printf("got to 051e\n"); + bc = s.patch.sustain; // half scale + + if (ea < bc) ea = bc; + + ea -= bc; + bc = ea; + + ea = (ea * s.patch.decay) >> 16; + ea += s.patch.sustain; + //printf("returning from decay phase\n"); + goto h0590; + + h0538: + //printf("got to 0x0538\n"); + if (!ff07) goto h054a; // note on? if not skip ahead + // 053c + if (ff08) goto h0517; + ff07 = false; + h054a: + //printf("release phase\n"); + ff33 = false; + ff08 = false; + bc = ea; + ea = (ea*s.patch.release)>>16; + // printf("returning from release phase\n"); + goto h0590; + + h0563: + // printf("attack phase\n"); + ff08 = false; + ea += s.patch.attack; + if (ea & 0xc000) { + ea = 0x3fff; + ff33 = true; + ff08 = true; + } + + h0590: + env = ea; + //printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33); + } static inline float poly3blep0(float t) { @@ -130,7 +192,8 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) { out = y; // widthDelay = pulseWidth; - vr58c106 += ((env - vr58c106) * 0.0075); + vr58c106 += (((env/16383.0) - vr58c106) * 0.0075); buffer[i] += (0.25 * out * vr58c106); } } + diff --git a/plugin/voice.hpp b/plugin/voice.hpp index 3cc7dda..8b2c16f 100644 --- a/plugin/voice.hpp +++ b/plugin/voice.hpp @@ -16,20 +16,24 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#pragma once - +#pragma once #include +//uint16_t attack_table[128]; +//uint16_t decay_table[128]; + class Synth; class Patch { public: - float saw, sqr, sub; + float saw=1, sqr, sub; + uint16_t attack=0x1ff, decay=0x1ff, sustain=0x1000, release=0x1ff; }; class Voice { public: - uint8_t note = 72; + // uint8_t note = 72; + uint8_t note = 60; void on(uint32_t key, bool reset); @@ -39,7 +43,7 @@ class Voice { void run(Synth &s, float *buffer, uint32_t samples); - void gate(); + void gate(Synth &s); private: enum { ATTACK, @@ -51,11 +55,19 @@ class Voice { K_ON, K_SUSTAIN } keyState = K_OFF; - float phase = 0, omega = 260 / 48000.0, subosc = 1; - float env, target; - float delay; -uint8_t pulseStage = 0; + bool ff00; // reset bit + bool ff07; // status bit + bool ff08; // set to indicate attack phase complete + bool ff10; // note on bit + bool ff11; // sustain flag + bool ff33; // releasing flag + uint16_t env; + + float phase = 0, omega = 260 / 48000.0, subosc = 1; + // float env, target; + float delay; + uint8_t pulseStage = 0; float pw_rc = 0; float vr58c106 = 0; @@ -69,4 +81,6 @@ class Synth { float lastpw = 0; uint32_t blockLeft; uint32_t framesLeft = 0; + }; +