diff --git a/plugin/chassis.cpp b/plugin/chassis.cpp index 1636f08..9e999be 100644 --- a/plugin/chassis.cpp +++ b/plugin/chassis.cpp @@ -20,116 +20,167 @@ START_NAMESPACE_DISTRHO -Chassis::Chassis() : Plugin(kParameterCount, 0, 0), sampleRate(getSampleRate()) { // one parameter, no programs, no states +Chassis::Chassis() : Plugin(parameterCount, 0, 0), sampleRate(getSampleRate()) { // one parameter, no programs, no states } // Initialisation functions void Chassis::initParameter(uint32_t index, Parameter ¶meter) { switch (index) { - case k_saw: + case paramSaw: parameter.hints = kParameterIsAutomatable | kParameterIsBoolean; parameter.name = "Saw"; - parameter.symbol = "saw"; + parameter.symbol = "ch_saw"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; parameter.ranges.def = 127.0f; parameter.midiCC = 17; break; - case k_sqr: + case paramSqr: parameter.hints = kParameterIsAutomatable | kParameterIsBoolean; parameter.name = "Square"; - parameter.symbol = "sqr"; + parameter.symbol = "ch_sqr"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; - parameter.ranges.def = 0.0f; + parameter.ranges.def = 127.0f; parameter.midiCC = 16; break; - case k_sub: + case paramSub: parameter.hints = kParameterIsAutomatable; parameter.name = "Sub Osc"; - parameter.symbol = "sub"; + parameter.symbol = "ch_sub"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; parameter.ranges.def = 0.0f; parameter.midiCC = 18; break; - case k_attack: + case paramAttack: parameter.hints = kParameterIsAutomatable; parameter.name = "Attack"; - parameter.symbol = "attack"; + parameter.symbol = "ch_attack"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; - parameter.ranges.def = 0.0f; + parameter.ranges.def = 59.0f; parameter.midiCC = 73; break; - case k_decay: + case paramDecay: parameter.hints = kParameterIsAutomatable; parameter.name = "Decay"; - parameter.symbol = "decay"; + parameter.symbol = "ch_decay"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; - parameter.ranges.def = 0.0f; + parameter.ranges.def = 32.0f; parameter.midiCC = 75; break; - case k_sustain: + case paramSustain: parameter.hints = kParameterIsAutomatable; parameter.name = "Sustain"; - parameter.symbol = "sustain"; + parameter.symbol = "ch_sustain"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; - parameter.ranges.def = 0.0f; + parameter.ranges.def = 86.0f; parameter.midiCC = 27; break; - case k_release: + case paramRelease: parameter.hints = kParameterIsAutomatable; parameter.name = "Release"; - parameter.symbol = "release"; + parameter.symbol = "ch_release"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 127.0f; + parameter.ranges.def = 40.0f; + parameter.midiCC = 72; + break; + + case paramEnvGate: + parameter.hints = kParameterIsAutomatable | kParameterIsBoolean; + parameter.name = "Env / Gate"; + parameter.symbol = "ch_envgate"; parameter.ranges.min = 0.0f; parameter.ranges.max = 127.0f; parameter.ranges.def = 0.0f; - parameter.midiCC = 72; + parameter.midiCC = 25; + break; + + case paramVCALevel: + parameter.hints = kParameterIsAutomatable; + parameter.name = "VCA Level"; + parameter.symbol = "ch_vcalevel"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 127.0f; + parameter.ranges.def = 40.0f; + parameter.midiCC = 26; break; } } void Chassis::setParameterValue(uint32_t index, float value) { + // printf("setparametervalue %d\n", index); switch (index) { - case k_saw: - s.patch.saw = value / 127.0f; + case paramSaw: + s.patchRam.switch1 &= 0xef; + s.patchRam.switch1 |= (value > 63) << 4; break; - case k_sqr: - s.patch.sqr = value / 127.0f; + case paramSqr: + s.patchRam.switch1 &= 0xf7; + s.patchRam.switch1 |= (value > 63) << 3; break; - case k_sub: - s.patch.sub = value / 127.0f; + case paramSub: + s.patchRam.sub = value; break; - case k_attack: - s.patch.attack = attack_table[(int)value]; + case paramAttack: + s.patchRam.env_a = value; break; - case k_decay: - s.patch.decay = decay_table[(int)value]; + case paramDecay: + s.patchRam.env_d = value; break; - case k_sustain: - s.patch.sustain = (int)value << 7; + case paramSustain: + s.patchRam.env_s = value; break; - case k_release: - s.patch.release = decay_table[(int)value]; + case paramRelease: + s.patchRam.env_r = value; + break; + case paramEnvGate: + s.patchRam.switch2 &= 0xfb; + s.patchRam.switch2 |= (value > 63) << 2; + break; + case paramVCALevel: + s.patchRam.vca = value; break; } } -/* float Chassis::getParameterValue(uint32_t index) const { + // printf("getparametervalue %d\n", index); + + switch (index) { + case paramSaw: + return (s.patchRam.switch1 & 0x10) ? 127.0f : 0.0f; + break; + case paramSqr: + return (s.patchRam.switch1 & 0x08) ? 127.0f : 0.0f; + break; + case paramAttack: + return s.patchRam.env_a; + break; + case paramDecay: + return s.patchRam.env_d; + break; + case paramSustain: + return s.patchRam.env_s; + break; + case paramRelease: + return s.patchRam.env_r; + break; + } return 0; } -*/ + void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) { port.groupId = kPortGroupStereo; Plugin::initAudioPort(input, index, port); @@ -137,16 +188,7 @@ void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) { if (!input && index == 0) port.name = "Left Out"; if (!input && index == 1) port.name = "Right Out"; } -/* -void Chassis::initProgramName(uint32_t index, String &programName) { - programName = "init"; -} -void Chassis::loadProgram(uint32_t index) { - prog_offset = (index & 0x3f) << 7; - program = index + 1; -} -*/ // Processing functions void Chassis::activate() { @@ -162,7 +204,6 @@ void Chassis::deactivate() { void Chassis::noteOn(uint8_t note) { uint32_t i; - //printf("noteon %d %d\n", note, vPtr); for (i = 0; i < NUM_VOICES; i++) { vPtr++; if (vPtr == NUM_VOICES) vPtr = 0; @@ -183,7 +224,7 @@ void Chassis::noteOn(uint8_t note) { } void Chassis::noteOff(uint8_t note) { - // printf("noteoff %d\n", note); + // printf("noteoff %d\n", note); for (uint32_t i = 0; i < NUM_VOICES; i++) { if (s.voice[i].note == note && !s.voice[i].isFree()) { s.voice[i].off(); @@ -196,7 +237,6 @@ void Chassis::noteOff(uint8_t note) { void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) { // printf("doMidi() handling events from %d to %d\n", lastEvent, timeLimit); uint32_t i; - uint8_t val = 0; if (count == 0) return; for (i = lastEvent; i < count; i++) { // printf("doMidi event number %d of %d %02x %02x\n", i, count, ev[i].data[0], ev[i].data[1]); @@ -208,35 +248,6 @@ void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) { case 0x80: noteOff(ev[i].data[1]); break; -#if 0 - case 0xb0: - //printf("cc %02x %02x\n", ev[i].data[1], ev[i].data[2]); - val = ev[i].data[2]; // get control value - switch (ev[i].data[1]) { - case 16: - s.patch.sqr = val / 127.0f; - break; - case 17: - s.patch.saw = val / 127.0f; - break; - 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; -#endif } } lastEvent = i; diff --git a/plugin/chassis.hpp b/plugin/chassis.hpp index 5a9696e..efb114e 100644 --- a/plugin/chassis.hpp +++ b/plugin/chassis.hpp @@ -32,14 +32,16 @@ START_NAMESPACE_DISTRHO class Chassis : public Plugin { public: enum Parameters { - k_saw, - k_sqr, - k_sub, - k_attack, - k_decay, - k_sustain, - k_release, - kParameterCount + paramSaw, + paramSqr, + paramSub, + paramAttack, + paramDecay, + paramSustain, + paramRelease, + paramEnvGate, + paramVCALevel, + parameterCount }; Chassis(); @@ -59,7 +61,7 @@ class Chassis : public Plugin { void initParameter(uint32_t index, Parameter ¶meter) override; void setParameterValue(uint32_t index, float value) override; - // float getParameterValue(uint32_t index) const override; + float getParameterValue(uint32_t index) const override; // void initProgramName(uint32_t index, String &programName) override; // void loadProgram(uint32_t index) override; @@ -84,40 +86,6 @@ 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 c537e4e..e5e195b 100644 --- a/plugin/voice.cpp +++ b/plugin/voice.cpp @@ -27,29 +27,38 @@ bool Voice::isFree() { } void Voice::on(uint32_t key, bool reset = 0) { - - //printf("======================================================================================\n"); - ff10 = true; + // printf("======================================================================================\n"); + // what's with the crazy private variables and all the gotos with crazy labels? + // this code emulates the 78C11 code directly (probably inefficiently) + // to allow for documenting what the variables actually do + // they're really bitfields holding a bit for each voice - ff07 = true; + // this current implementation doesn't reset the voice + (void)reset; + + ff10 = true; // note held from keyboard + ff07 = true; // attack phase if (note == key) goto h0144; note = key; if (ff11) goto h013e; - h0132: - if (ff33) goto h0149; +h0132: + if (ff33) goto h0149; // sustained ff33 = false; goto h0149; - h013e: - ff00 = true; +h013e: + ff00 = true; // in a real one, voice counter needs programmed goto h0149; - h0144: - if (!ff11) goto h0132; +h0144: + if (!ff11) goto h0132; // unsure, copied from ff10 at start of mainloop - 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; +h0149: + // printf("after 0144h, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33); + + // this is in the wrong place really but is the equivalent of programming the counter + // and VCO ramp DAC + omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f; } void Voice::off() { @@ -59,17 +68,14 @@ void Voice::off() { ff33 = false; } - //printf("after note off, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33); + // printf("after note off, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33); } void Voice::gate(Synth &s) { - - uint16_t bc, ea=env; + uint16_t bc, ea = env; ff11 = ff10; - - // 0509 if (!ff11) goto h0538; @@ -79,55 +85,50 @@ void Voice::gate(Synth &s) { // 0513 if (!ff07) goto h051e; - // 0517 - h0517: - //printf("got to 0517\n"); +h0517: ff07 = false; - h051e: - - //printf("got to 051e\n"); - bc = s.patch.sustain; // half scale +h051e: + bc = s.patchRam.env_s << 7; // 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"); + ea = (ea * decay_table[s.patchRam.env_d]) >> 16; + ea += s.patchRam.env_s << 7; + // printf("returning from decay phase\n"); goto h0590; - h0538: - //printf("got to 0x0538\n"); +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"); +h054a: + // printf("release phase\n"); ff33 = false; ff08 = false; bc = ea; - ea = (ea*s.patch.release)>>16; - // printf("returning from release phase\n"); + ea = (ea * decay_table[s.patchRam.env_r]) >> 16; + // printf("returning from release phase\n"); goto h0590; - h0563: - // printf("attack phase\n"); +h0563: + // printf("attack phase\n"); ff08 = false; - ea += s.patch.attack; + ea += attack_table[s.patchRam.env_a]; if (ea & 0xc000) { ea = 0x3fff; ff33 = true; ff08 = true; } - h0590: +h0590: env = ea; - //printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33); - + // printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33); } static inline float poly3blep0(float t) { @@ -140,7 +141,13 @@ static inline float poly3blep1(float t) { } void Voice::run(Synth &s, float *buffer, uint32_t samples) { - float y, out, pw = 0, t; + float y, out, pw = 0.5, t; + + float sqr = (s.patchRam.switch1 & 0x08) ? 0.175 : 0; + float saw = (s.patchRam.switch1 & 0x10) ? 0.220 : 0; + float sub = (s.patchRam.sub / 127.0f) * 0.275; + + float gain = 0.5 * powf(2, (s.patchRam.vca / 64.0f) - 1); for (uint32_t i = 0; i < samples; i++) { y = delay; @@ -148,21 +155,19 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) { phase += omega; - float pulseWidth = 0.5; // pwm[i]; - - // if(pulseWidth > 1) pulseWidth = 1; - // if(pulseWidth < 0) pulseWidth = 0; + // if(pw > 1) pw = 1; + // if(pw < 0) pw = 0; while (true) { if (pulseStage == 0) { - if (phase < pulseWidth) break; + if (phase < pw) break; #if 1 - float t = (phase - pulseWidth) / omega; + t = (phase - pw) / omega; #else - float t = (phase - pulseWidth) / (widthDelay - pulseWidth + freq); + t = (phase - pw) / (widthDelay - pw + freq); #endif - y -= poly3blep0(t) * s.patch.sqr; - delay -= poly3blep1(t) * s.patch.sqr; + y -= poly3blep0(t) * sqr; + delay -= poly3blep1(t) * sqr; pulseStage = 1; } @@ -170,11 +175,11 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) { if (phase < 1) break; float t = (phase - 1) / omega; - y += poly3blep0(t) * (s.patch.saw + s.patch.sqr); - delay += poly3blep1(t) * (s.patch.saw + s.patch.sqr); + y += poly3blep0(t) * (saw + sqr); + delay += poly3blep1(t) * (saw + sqr); - y -= poly3blep0(t) * (s.patch.sub * subosc); - delay -= poly3blep1(t) * (s.patch.sub * subosc); + y -= poly3blep0(t) * (sub * subosc); + delay -= poly3blep1(t) * (sub * subosc); pulseStage = 0; phase -= 1; @@ -182,18 +187,17 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) { } } - delay += s.patch.saw * (1 - (2 * phase)); + delay += saw * (1 - (2 * phase)); - delay += s.patch.sqr * (pulseStage ? -1.f : 1.f); + delay += sqr * (pulseStage ? -1.f : 1.f); - delay += s.patch.sub * subosc; + delay += sub * subosc; // out = (2 * y) - 1; out = y; - // widthDelay = pulseWidth; + // widthDelay = pw; - vr58c106 += (((env/16383.0) - vr58c106) * 0.0075); - buffer[i] += (0.25 * out * vr58c106); + vr58c106 += (((env / 16383.0) - vr58c106) * 0.0075); + buffer[i] += (gain * out * vr58c106); } } - diff --git a/plugin/voice.hpp b/plugin/voice.hpp index 0947cb7..5c0c282 100644 --- a/plugin/voice.hpp +++ b/plugin/voice.hpp @@ -16,17 +16,17 @@ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#pragma once +#pragma once #include -//uint16_t attack_table[128]; -//uint16_t decay_table[128]; +// uint16_t attack_table[128]; +// uint16_t decay_table[128]; class Synth; class Patch { public: - float saw=1, sqr, sub; + float saw, sqr, sub; uint16_t attack, decay, sustain, release; }; @@ -55,12 +55,12 @@ class Voice { K_ON, K_SUSTAIN } keyState = K_OFF; - bool ff00=0; // reset bit - bool ff07=0; // status bit - bool ff08=0; // set to indicate attack phase complete - bool ff10=0; // note on bit - bool ff11=0; // sustain flag - bool ff33=0; // releasing flag + bool ff00 = 0; // reset bit + bool ff07 = 0; // status bit + bool ff08 = 0; // set to indicate attack phase complete + bool ff10 = 0; // note on bit + bool ff11 = 0; // sustain flag + bool ff33 = 0; // releasing flag uint16_t env; @@ -71,6 +71,39 @@ class Voice { float pw_rc = 0; float vr58c106 = 0; + 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}; }; class Synth { @@ -82,5 +115,33 @@ class Synth { uint32_t blockLeft; uint32_t framesLeft = 0; + // okay, not the greatest, this right here + // this struct contains the bytes that make up a Juno 106 patch in + // sysex order, exactly as they'd be transmitted or received by a + // real one. + // the horrifying implication here is that we can just shunt this + // around and memcpy() values from sysex on top of it + + struct { + uint8_t lfo_rate = 57; + uint8_t lfo_delay = 45; + uint8_t lfo_dco = 0; + uint8_t lfo_pwm = 55; + uint8_t noise = 0; + uint8_t vcf_cut = 85; + uint8_t vcf_res = 0; + uint8_t vcf_env = 0; + uint8_t vcf_lfo = 0; + uint8_t vcf_kyb = 108; + uint8_t vca = 52; + uint8_t env_a = 59; + uint8_t env_d = 32; + uint8_t env_s = 86; + uint8_t env_r = 40; + uint8_t sub = 0; + uint8_t switch1 = 26; + uint8_t switch2 = 24; + } patchRam; }; +