// ****************************************************************************************************** // * DW6000 controller for Arduino nano V3 * // * Author: PHOBoS * // * Date: Aug 30, 2018 * // ****************************************************************************************************** #include // use midi library MIDI_CREATE_DEFAULT_INSTANCE(); // use default midi configuration // ****************************************************************************************************** // * ARDUINO PINS SETUP * // ------------------------------------------------------------------------------------------------------ #define LED1 19 // number of digital output pin used for LED of switch 1 #define LED2 18 // number of digital output pin used for LED of switch 2 #define LED3 13 // number of digital output pin used for LED of switch 3 #define SW1 16 // number of digital input pin used for switch 1 #define SW2 15 // number of digital input pin used for switch 2 #define SW3 14 // number of digital input pin used for switch 3 #define dta_out 12 // number of digital output pin used for serial output Data #define ser_clk 11 // number of digital output pin used for serial Clock #define latch_out 10 // number of digital output pin used for serial output Latch #define DIP1 9 // number of digital input pin used for DIP switch 1 #define DIP2 8 // number of digital input pin used for DIP switch 2 #define DIP3 7 // number of digital input pin used for DIP switch 3 #define DIP4 6 // number of digital input pin used for DIP switch 4 #define mux_A 3 // number of digital output pin used for control line A of mux 1 & 2 #define mux_B 2 // number of digital output pin used for control line B of mux 1 & 2 #define mux_C 4 // number of digital output pin used for control line C of mux 1 & 2 #define mux_D 5 // number of digital output pin used for control line D of mux 1 & 2 #define ana_R 3 // number of (floating) analog input pin used to seed random generator #define ana_1 6 // number of analog input pin used to read output of mux 1 #define ana_2 7 // number of analog input pin used to read output of mux 2 // ****************************************************************************************************** // * KORG DW6000 SETUP * // ------------------------------------------------------------------------------------------------------ // KORG DW6000 parameter change values (from manual) // MIDI SysEx command = {exclusive, korg_id, format_id, dw6000_id, param_change, param_offset, param_value, eox} #define exclusive 0xF0 #define korg_id 0x42 #define format_id 0x30 #define dw6000_id 0x04 #define param_change 0x41 #define eox 0xF7 // KORG DW6000 parameter offset values (from manual) // send as 'param_offset' in SysEx command #define assign_mode_offset 0 #define bend_OSC_offset 0 #define port_time_offset 1 #define OSC1_level_offset 2 #define OSC2_level_offset 3 #define noise_level_offset 4 #define cutoff_offset 5 #define resonance_offset 6 #define VCF_env_int_offset 7 #define VCF_env_attack_offset 8 #define VCF_env_decay_offset 9 #define VCF_env_break_offset 10 #define VCF_env_slope_offset 11 #define VCF_env_sustain_offset 12 #define VCF_env_release_offset 13 #define VCA_env_attack_offset 14 #define VCA_env_decay_offset 15 #define VCA_env_break_offset 16 #define VCA_env_slope_offset 17 #define bend_VCF_offset 18 #define VCA_env_sustain_offset 18 #define OSC1_octave_offset 19 #define VCA_env_release_offset 19 #define OSC2_octave_offset 20 #define mod_gen_freq_offset 20 #define VCF_kbd_track_offset 21 #define mod_gen_delay_offset 21 #define VCF_env_polarity_offset 22 #define mod_gen_OSC_offset 22 #define chorus_offset 23 #define mod_gen_VCF_offset 23 #define OSC1_waveform_offset 24 #define OSC2_waveform_offset 24 #define OSC2_interval_offset 25 #define OSC2_detune_offset 25 // ****************************************************************************************************** // * PARAMETERS IDS * // ------------------------------------------------------------------------------------------------------ #define OSC1_octave 0 #define OSC1_waveform 1 #define OSC1_level 2 #define OSC2_octave 3 #define OSC2_waveform 4 #define OSC2_level 5 #define OSC2_interval 6 #define OSC2_detune 7 #define noise_level 8 #define port_time 9 #define mod_gen_freq 10 #define mod_gen_delay 11 #define mod_gen_OSC 12 #define mod_gen_VCF 13 #define cutoff 14 #define resonance 15 #define VCF_kbd_track 16 #define VCF_env_int 17 #define VCF_env_attack 18 #define VCF_env_decay 19 #define VCF_env_break 20 #define VCF_env_slope 21 #define VCF_env_sustain 22 #define VCF_env_release 23 #define VCA_env_attack 24 #define VCA_env_decay 25 #define VCA_env_break 26 #define VCA_env_slope 27 #define VCA_env_sustain 28 #define VCA_env_release 29 #define bend_OSC 30 #define bend_VCF 31 #define VCF_env_polarity 32 #define chorus 33 #define assign_mode 34 // values > 34 can be used for custom functions #define rpatch 40 // ****************************************************************************************************** // * FACTORY PRESETS * // ------------------------------------------------------------------------------------------------------ // factory preset values are copied from the user manual and entered in the same order. // values are converted to the appropriate MIDI SysEx bytes by the FACTORY PATCH LOADER. // // 11. OSC1_octave: 16/8/4 // 12. OSC1_waveform: 1~8 // 13. OSC1_level: 0~31 // 21. OSC2_octave: 16/8/4 // 22. OSC2_waveform: 1~8 // 23. OSC2_level: 0~31 // 24. OSC2_interval: 1/-3/3/4/5 // 25. OSC2_detune: 0~6 // 26. noise_level: 0~31 // 31. cutoff: 0~63 // 32. resonance: 0~31 // 33. VCF_kbd_track: 0/1/2 // 34. VCF_env_polarity: 1/2 // 35. VCF_env_int: 0~31 // 36. chorus: 0/1 // 41. VCF_env_attack 0~31 // 42. VCF_env_decay: 0~31 // 43. VCF_env_break 0~31 // 44. VCF_env_slope: 0~31 // 45. VCF_env_sustain: 0~31 // 46. VCF_env_release: 0~31 // 51. VCA_env_attack: 0~31 // 52. VCA_env_decay: 0~31 // 53. VCA_env_break: 0~31 // 54. VCA_env_slope: 0~31 // 55. VCA_env_sustain: 0~31 // 56. VCA_env_release: 0~31 // 61. mod_gen_freq: 0~31 // 62. mod_gen_delay: 0~31 // 63. mod_gen_OSC: 0~31 // 64. mod_gen_VCF: 0~31 // 71. bend_OSC: 0~12 // 72. bend_VCF: 0/1 // 73. port_time: 0/31 // --- assign_mode: 1/2/3 #define synth_brass 0 // factory preset #define bells_1 1 // factory preset #define acoustic_piano 2 // factory preset #define bowed_cellos 3 // factory preset #define boc 4 // custom preset #define drpad 5 // custom preset // PROG NO.: 11,12,13,21,22,23,24,25,26,31,32,33,34,35,36,41,42,43,44,45,46,51,52,53,54,55,56,61,62,63,64,71,72,73,ass // -------------------------------------------------------------------------------------------------------------------- const char synth_brass_val[35] = {16, 1,31,16, 1,31, 1, 5, 3, 6, 0, 1, 1,27, 1, 3,20,18,20,27,11, 0,31,31,28,28, 9, 8,11, 0, 0, 2, 0, 0, 1}; const char bells_1_val[35] = { 4, 8,31,16, 8,31, 5, 5, 0, 3, 0, 2, 1,25, 1, 0,24,22,25, 0,26, 0,31,26,26,29,31, 0, 0, 0, 0, 2, 0, 0, 1}; const char acoustic_piano_val[35] = {16, 3,31,16, 8,19, 1, 4, 0,38, 5, 1, 1, 6, 0, 0,13,13,17, 0,12, 0,19,21,21, 0, 9, 8, 0, 0, 0, 2, 0, 0, 1}; const char bowed_cellos_val[35] = {16, 1,31,16, 6,21, 1, 5, 0,31, 1, 2, 1, 5, 1, 0,16, 0, 0, 0,13,10,16,19,12,18,10, 8, 0, 3, 0, 2, 0, 0, 1}; const char boc_val[35] = { 4, 4,31,16, 1,31, 1, 4, 7,39, 3, 1, 2,15, 1,10, 9,31,10, 0,22,15,21,23,25,55,25, 1, 0, 6, 0, 2, 0, 0, 1}; const char drpad_val[35] = { 8, 7,31, 8, 2,22, 1, 3,10,15, 8, 1, 1,22, 1,25,13,13,21,13,17,17,24,26, 6,24, 9, 4,31, 3, 2, 2, 0,12, 2}; const char* factory_presets[] = {synth_brass_val, bells_1_val, acoustic_piano_val, bowed_cellos_val, boc_val, drpad_val}; // ****************************************************************************************************** // * LED DISPLAY CHARACTERS * // ------------------------------------------------------------------------------------------------------ // b.acfdge // -------- const byte dA[] = { B10111101, B10010000, B10100111, B10110110, B10011010, B00111110, B00111111, B10110000, B10111111, B10111110, B01000000, B00000010, B10011011 }; // egdfca.b // -------- const byte dB[] = { B10111101, B10010000, B11100101, B11110100, B11011000, B01111100, B01111101, B10110000, B11111101, B11111100, B00000010, B01000000, B11011001 }; // ****************************************************************************************************** // * DEFINE GLOBAL VARIABLES * // ------------------------------------------------------------------------------------------------------ const byte available_ctrls[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33}; byte control[35]; // array with parameters that the controls are assigned to byte param_offset = 0; // offset value for selected parameter byte param_offsets[35]; // array with all parameter offset values byte param_value = 0; // value of selected parameter byte param_values[41]; // array with all parameter values byte heinz[41]; // used for catch-up. 0: stored value < control, 1: stored value = control, 2: stored value > control. byte ctrl_val_stored[35]; // values of controls from previous read cycle byte ctrl_val_read[35]; // values of controls from current read cycle byte dta_out_A = 0; // clear display A byte dta_out_B = 0; // clear display B byte z = 0; // available controls byte C = 0; // control number byte id = 0; // parameter id number //byte button[8]; // stored button values after calibration byte sysexArray[] = {exclusive, korg_id, format_id, dw6000_id, param_change, param_offset, param_value, eox}; byte OMNI_on[] = {0xB0, 0x7D, 0x00}; // ###################################################################################################### // START OF SETUP # // ###################################################################################################### void setup(void) { // ****************************************************************************************************** // * CONTROLS SETUP * // ------------------------------------------------------------------------------------------------------ // MUX A control[0] = VCF_env_int; control[1] = cutoff; control[2] = resonance; control[3] = VCF_kbd_track; control[4] = VCF_env_attack; control[5] = VCF_env_decay; control[6] = VCF_env_break; control[7] = VCF_env_slope; control[8] = VCF_env_sustain; control[9] = mod_gen_VCF; control[10] = OSC2_detune; control[11] = port_time; control[12] = VCF_env_release; control[13] = mod_gen_OSC; control[14] = mod_gen_delay; control[15] = mod_gen_freq; // MUX B control[16] = OSC1_waveform; control[17] = OSC1_octave; control[18] = OSC1_level; control[19] = noise_level; control[20] = OSC2_waveform; control[21] = OSC2_octave; control[22] = OSC2_level; control[23] = OSC2_interval; control[24] = VCA_env_attack; control[25] = VCA_env_decay; control[26] = VCA_env_break; control[27] = VCA_env_slope; control[28] = VCA_env_sustain; control[29] = VCA_env_release; control[31] = chorus; // button 1 control[32] = VCF_env_polarity; // button 2 control[33] = rpatch; // button 3 // ****************************************************************************************************** // create array with parameter offset values (DO NOT ALTER!) // ------------------------------------------------------------------------------------------------------ param_offsets[OSC1_octave] = OSC1_octave_offset; param_offsets[OSC1_waveform] = OSC1_waveform_offset; param_offsets[OSC1_level] = OSC1_level_offset; param_offsets[OSC2_octave] = OSC2_octave_offset; param_offsets[OSC2_waveform] = OSC2_waveform_offset; param_offsets[OSC2_level] = OSC2_level_offset; param_offsets[OSC2_interval] = OSC2_interval_offset; param_offsets[OSC2_detune] = OSC2_detune_offset; param_offsets[noise_level] = noise_level_offset; param_offsets[VCA_env_attack] = VCA_env_attack_offset; param_offsets[VCA_env_decay] = VCA_env_decay_offset; param_offsets[VCA_env_break] = VCA_env_break_offset; param_offsets[VCA_env_slope] = VCA_env_slope_offset; param_offsets[VCA_env_sustain] = VCA_env_sustain_offset; param_offsets[VCA_env_release] = VCA_env_release_offset; param_offsets[port_time] = port_time_offset; param_offsets[VCF_kbd_track] = VCF_kbd_track_offset; param_offsets[VCF_env_int] = VCF_env_int_offset; param_offsets[VCF_env_attack] = VCF_env_attack_offset; param_offsets[VCF_env_decay] = VCF_env_decay_offset; param_offsets[VCF_env_break] = VCF_env_break_offset; param_offsets[VCF_env_slope] = VCF_env_slope_offset; param_offsets[VCF_env_sustain] = VCF_env_sustain_offset; param_offsets[VCF_env_release] = VCF_env_release_offset; param_offsets[cutoff] = cutoff_offset; param_offsets[resonance] = resonance_offset; param_offsets[mod_gen_freq] = mod_gen_freq_offset; param_offsets[mod_gen_delay] = mod_gen_delay_offset; param_offsets[mod_gen_OSC] = mod_gen_OSC_offset; param_offsets[mod_gen_VCF] = mod_gen_VCF_offset; param_offsets[bend_OSC] = bend_OSC_offset; param_offsets[bend_VCF] = bend_VCF_offset; param_offsets[VCF_env_polarity] = VCF_env_polarity_offset; param_offsets[chorus] = chorus_offset; param_offsets[assign_mode] = assign_mode_offset; // ****************************************************************************************************** // * CONFIGURE ARDUINO PINS * // ------------------------------------------------------------------------------------------------------ pinMode(LED_BUILTIN, OUTPUT); pinMode(ser_clk, OUTPUT); pinMode(dta_out, OUTPUT); pinMode(latch_out, OUTPUT); pinMode(mux_A, OUTPUT); pinMode(mux_B, OUTPUT); pinMode(mux_C, OUTPUT); pinMode(mux_D, OUTPUT); pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); pinMode(SW1,INPUT_PULLUP); pinMode(SW2,INPUT_PULLUP); pinMode(SW3,INPUT_PULLUP); pinMode(DIP1,INPUT_PULLUP); pinMode(DIP2,INPUT_PULLUP); pinMode(DIP3,INPUT_PULLUP); pinMode(DIP4,INPUT_PULLUP); // ****************************************************************************************************** // * MIDI CONFIG * // ------------------------------------------------------------------------------------------------------ MIDI.begin(MIDI_CHANNEL_OMNI); // set midi channels to OMNI MIDI.turnThruOff(); // turn midi thru mode off Serial.write(OMNI_on, 3); // set synth to OMNI and turn all notes off SEND_SERIAL(); // send serial data to clear displays SHOW_START(); // show some fancy display action on startup MIDI.setHandleNoteOn(MyHandleNoteOn); // setHandleNoteOn (byte channel, byte note, byte velocity) MIDI.setHandleNoteOff(MyHandleNoteOff); // setHandleNoteOff (byte channel, byte note, byte velocity) MIDI.setHandleControlChange(MyHandleCC); // setHandleControlChange (byte channel, byte number, byte value) MIDI.setHandlePitchBend(MyHandlePB); // setHandlePitchBend (byte channel, int bend) MIDI.setHandleProgramChange(MyHandlePC); // setHandleProgramChange (byte channel, byte number) MIDI.setHandleSystemExclusive(MyHandleSysEx); // setHandleSystemExclusive (byte *array, unsigned size) delay(100); // ****************************************************************************************************** // * STARTUP PARAMETER VALUES * // ------------------------------------------------------------------------------------------------------ randomSeed(analogRead(ana_R)); // use floating analog input as seed value for random heinz[31] = 1; // preset values for controls that don't need catch-up heinz[32] = 1; heinz[33] = 1; heinz[40] = 1; LOAD_PRESETS(synth_brass); // convert values from factory presets and send MIDI SySex commands // also stores the parameter values in parameter_values[] delay(50); // ------------------------------------------------------------------------------------------------------ // load control parameters for (z = 0; z <= 32; z++) { // read controls and store values but don't send MIDI SysEx commands C = available_ctrls[z]; // only read available controls id = control[C]; // parameter id corresponding with control // ------------------------------------------------------------------------------------------------------ READ_CONTROL(C); // read current control value // NOTE: control values are read in order of controls // => value is stored in ctrl_val_read[C], 6 bits value for pots, 1 bit for buttons // ------------------------------------------------------------------------------------------------------ ctrl_val_stored[C] = ctrl_val_read[C]; // overwrite stored value with new value // ctrl_val_stored & ctrl_val_read have values stores in order of controls } } // ###################################################################################################### // END OF SETUP # // ###################################################################################################### // ###################################################################################################### // MAIN PROGRAM # // ###################################################################################################### void loop() { MIDI.read(); // check if Midi data has been received. while (Serial.available() <= 0) { CONTROLLER(); // read Controls when there is no Midi data } } // ###################################################################################################### // END OF MAIN PROGRAM # // ###################################################################################################### // ###################################################################################################### // FUNCTIONS # // ###################################################################################################### // ****************************************************************************************************** // MIDI THRU & MERGER * // ------------------------------------------------------------------------------------------------------ // MIDI Note ON void MyHandleNoteOn(byte channel, byte pitch, byte velocity) { MIDI.sendNoteOn(pitch, velocity, channel); } // MIDI Note Off void MyHandleNoteOff(byte channel, byte pitch, byte velocity) { MIDI.sendNoteOff(pitch, velocity, channel); } // MIDI Pitch Bend void MyHandlePB(byte channel, int bend) { MIDI.sendPitchBend(bend, channel); } // MIDI Control Change void MyHandleCC(byte channel, byte number, byte value) { switch (number) { case 1: if (digitalRead(DIP2) == 0) {MIDI.sendControlChange(number, value, channel);} break; // 1. OSC Modulation: Generally this CC controls a vibrato effect (pitch, loudness, brighness). case 2: MIDI.sendControlChange(number, value, channel); break; // 2. VCF Modulation case 7: MIDI.sendControlChange(number, value, channel); break; // 7. Volume: Control the volume of the channel case 64: MIDI.sendControlChange(number, value, channel); break; // 64. Damper Pedal/Sustain Pedal: On/Off switch that controls sustain. 0 to 63 = Off, 64 to 127 = On case 65: if (digitalRead(DIP3) == 0) {MIDI.sendControlChange(number, value, channel);} break; // 65. Portamento On/Off Switch On/Off switch. 0 to 63 = Off, 64 to 127 = On case 123: MIDI.sendControlChange(number, value, channel); break; // 123. All Notes Off: Mutes all sounding notes. case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: customCC(number, value); break; // 20~30. Custom (see customCC) default: break; } } // MIDI Program Change void MyHandlePC(byte channel, byte number) { if (digitalRead(DIP1) == 0) { MIDI.sendProgramChange(number, channel); } } // MIDI SysEx void MyHandleSysEx(byte* receivedSysEx, unsigned size_) { if (receivedSysEx[4] == 0x41) { // received SysEx is parameter change, ignore all other SysEx commands param_value = R_SYSEX_CONVERTER(receivedSysEx[5], receivedSysEx[6]); sysexArray[5] = receivedSysEx[5]; // set parameter offset value sysexArray[6] = param_value; // set new parameter value SEND_SYSEX(); } } void SEND_SYSEX() { Serial.write(sysexArray, 8); } void SEND_SERIAL() { digitalWrite(latch_out, LOW); shiftOut(dta_out, ser_clk, MSBFIRST, dta_out_A); shiftOut(dta_out, ser_clk, MSBFIRST, dta_out_B); digitalWrite(latch_out, HIGH); } // ****************************************************************************************************** // * CUSTOM CONTOL CHANGE * // ------------------------------------------------------------------------------------------------------ // convert MIDI CC20~CC31 to sysex messages void customCC(byte CC, byte val) { switch (CC) { case 20: id = OSC1_waveform; break; // 0x14 case 21: id = OSC1_level; break; // 0x15 case 22: id = OSC2_waveform; break; // 0x16 case 23: id = OSC2_level; break; // 0x17 case 24: id = OSC2_detune; break; // 0x18 case 25: id = noise_level; break; // 0x19 case 26: id = mod_gen_freq; break; // 0x1A case 27: id = mod_gen_OSC; break; // 0x1B case 28: id = mod_gen_VCF; break; // 0x1C case 29: id = cutoff; break; // 0x1D case 30: id = resonance; break; // 0x1E default: break; } PARAMETER_CONVERTER(id, 0, (val >> 1)); // change value from 7 to 6 bits before converting sysexArray[5] = param_offsets[id]; // set parameter offset value sysexArray[6] = PARAMETER_MERGER(id); // set new parameter value SEND_SYSEX(); // send MIDI SysEx command } // ****************************************************************************************************** // * RECEIVED SYSEX CONVERTER * // ------------------------------------------------------------------------------------------------------ // stores received sysex values // ignores sysex commands assigned to buttons // merges values that share bytes byte R_SYSEX_CONVERTER(byte r_sysex_offset, byte r_sysex_value) { byte merged_value = 0; switch (r_sysex_offset) { case 0: // assign_mode [b5-b4] or bend_OSC [b3-b0] param_values[bend_OSC] = r_sysex_value & B00001111; // store new bend_OSC value (AND value with B00001111 to ignore assign_mode bits) merged_value = param_values[bend_OSC] | param_values[assign_mode]; break; case 1: // port_time param_values[port_time] = r_sysex_value; // store new port_time value break; case 2: // OSC1_level param_values[OSC1_level] = r_sysex_value; // store new OSC1_level value break; case 3: // OSC2_level param_values[OSC2_level] = r_sysex_value; // store new OSC2_level value break; case 4: // noise_level param_values[noise_level] = r_sysex_value; // store new noise_level value break; case 5: // cutoff param_values[cutoff] = r_sysex_value; // store new cutoff value break; case 6: // resonance param_values[resonance] = r_sysex_value; // store new resonance value break; case 7: // VCF_env_int param_values[VCF_env_int] = r_sysex_value; // store new VCF_env_int value break; case 8: // VCF_env_attack param_values[VCF_env_attack] = r_sysex_value; // store new VCF_env_attack value break; case 9: // VCF_env_decay param_values[VCF_env_decay] = r_sysex_value; // store new VCF_env_decay value break; case 10: // VCF_env_break param_values[VCF_env_break] = r_sysex_value; // store new VCF_env_break value break; case 11: // VCF_env_slope param_values[VCF_env_slope] = r_sysex_value; // store new VCF_env_slope value break; case 12: // VCF_env_sustain param_values[VCF_env_sustain] = r_sysex_value; // store new VCF_env_sustain value break; case 13: // VCF_env_release param_values[VCF_env_release] = r_sysex_value; // store new VCF_env_release value break; case 14: // VCA_env_attack param_values[VCA_env_attack] = r_sysex_value; // store new VCA_env_attack value break; case 15: // VCA_env_decay param_values[VCA_env_decay] = r_sysex_value; // store new VCA_env_decay value break; case 16: // VCA_env_break param_values[VCA_env_break] = r_sysex_value; // store new VCA_env_break value break; case 17: // VCA_env_slope param_values[VCA_env_slope] = r_sysex_value; // store new resonance value break; case 18: // bend_VCF [b5] or VCA_env_sustain [b4-b0] param_values[bend_VCF] = r_sysex_value & B00100000; // store new bend_VCF value (AND value with B00100000 to ignore VCA_env_sustain bits) param_values[VCA_env_sustain] = r_sysex_value & B00011111; // store new VCA_env_sustain value (AND value with B00011111 to ignore bend_VCF bits) merged_value = param_values[bend_VCF] | param_values[VCA_env_sustain]; break; case 19: // OSC1_octave [b6-b5] or VCA_env_release [b4-b0] param_values[OSC1_octave] = r_sysex_value & B01100000; // store new OSC1_octave value (AND value with B01100000 to ignore VCA_env_release bits) param_values[VCA_env_release] = r_sysex_value & B00011111; // store new VCA_env_release value (AND value with B00011111 to ignore OSC1_octave bits) merged_value = param_values[OSC1_octave] | param_values[VCA_env_release]; break; case 20: // OSC2_octave [b6-b5] or mod_gen_freq [b4-b0] param_values[OSC2_octave] = r_sysex_value & B01100000; // store new OSC2_octave value (AND value with B01100000 to ignore mod_gen_freq bits) param_values[mod_gen_freq] = r_sysex_value & B00011111; // store new mod_gen_freq value (AND value with B00011111 to ignore OSC2_octave bits) merged_value = param_values[OSC2_octave] | param_values[mod_gen_freq]; break; case 21: // VCF_kbd_track [b6-b5] or mod_gen_delay [b4-b0] param_values[VCF_kbd_track] = r_sysex_value & B01100000; // store new VCF_kbd_track value (AND value with B01100000 to ignore mod_gen_delay bits) param_values[mod_gen_delay] = r_sysex_value & B00011111; // store new mod_gen_delay value (AND value with B00011111 to ignore VCF_kbd_track bits) merged_value = param_values[VCF_kbd_track] | param_values[mod_gen_delay]; break; case 22: // VCF_env_polarity [b5] or mod_gen_OSC [b4-b0] // param_values[VCF_env_polarity]= r_sysex_value & B00100000; // store new VCF_env_polarity value (AND value with B00100000 to ignore mod_gen_OSC bits) param_values[mod_gen_OSC] = r_sysex_value & B00011111; // store new mod_gen_OSC value (AND value with B00011111 to ignore VCF_env_polarity bits) merged_value = param_values[VCF_env_polarity] | param_values[mod_gen_OSC]; break; case 23: // chorus [b5] or mod_gen_VCF [b4-b0] // param_values[chorus] = r_sysex_value & B00100000; // store new chorus value (AND value with B00100000 to ignore mod_gen_VCF bits) param_values[mod_gen_VCF] = r_sysex_value & B00011111; // store new mod_gen_VCF value (AND value with B00011111 to ignore chorus bits) merged_value = param_values[chorus] | param_values[mod_gen_VCF]; break; case 24: // OSC1_waveform [b5-b3] or OSC2_waveform [b2-b0] param_values[OSC1_waveform] = r_sysex_value & B00111000; // store new OSC1_waveform value (AND value with B00111000 to ignore OSC2_waveform bits) param_values[OSC2_waveform] = r_sysex_value & B00000111; // store new OSC2_waveform value (AND value with B00000111 to ignore OSC1_waveform bits) merged_value = param_values[OSC1_waveform] | param_values[OSC2_waveform]; break; case 25: // OSC2_interval [b5-b3] or OSC2_detune [b2-b0] param_values[OSC2_interval] = r_sysex_value & B00111000; // store new OSC1_waveform value (AND value with B00111000 to ignore OSC2_detune bits) param_values[OSC2_detune] = r_sysex_value & B00000111; // store new OSC2_detune value (AND value with B00000111 to ignore OSC2_interval bits) merged_value = param_values[OSC2_interval] | param_values[OSC2_detune]; break; } if (r_sysex_offset >= 1 && r_sysex_offset <= 17) { merged_value = r_sysex_value; } return(merged_value); } // ****************************************************************************************************** // MAIN CONTROLLER PROGRAM * // ------------------------------------------------------------------------------------------------------ // z: counter value // C: control number // id: parameter id associated with control // param_value: value for parameter, combined value if shared byte // param_offsets[]: array with parameter offset values (from manual) // ctrl_val_read[]: array with read values of controls // ctrl_val_stored[]: array with stored values of controls void CONTROLLER() { if (z > 32) {z = 0;} C = available_ctrls[z]; // only read available controls id = control[C]; // parameter id corresponding with control // ------------------------------------------------------------------------------------------------------ READ_CONTROL(C); // read current control value // NOTE: control values are read in order of controls // => value is stored in ctrl_val_read[C], 6 bits value for pots, 1 bit for buttons // ------------------------------------------------------------------------------------------------------ if (ctrl_val_read[C] != ctrl_val_stored[C]) { // compare read control value with stored control value to check if it has changed // ------------------------------------------------------------------------------------------------------ // HEINZ CATCH-UP: // adds catch-up to controls when the pot value is different from the stored parameter value // when control gets changed compare current value (converted to parameter) with stored value // if stored value is smaller: don't update param value untill control value is equal or smaller than stored value // if stored value is larger: don't update param value untill control value is equal or larger than stored value if (C < 30) { // ignore for buttons byte stored_param = param_values[id]; // lookup current stored value of adjusted parameter and store in temporary variable PARAMETER_CONVERTER(id, C, ctrl_val_stored[C]); // convert stored value of control to parameter value for comparison PARAM_DISPLAY(id); if ((param_values[id] == stored_param) || // if the value is the same or (param_values[id] > stored_param && heinz[id] == 0) || // if the value is larger but was smaller or (param_values[id] < stored_param && heinz[id] == 2)) { // if the value is smaller but was larger heinz[id] = 1; // use new parameter value dta_out_A = dta_out_A & ~dA[10]; dta_out_B = dta_out_B & ~dB[10]; } else { if (param_values[id] > stored_param) { // if the new value is larger or heinz[id] = 2; dta_out_A = dta_out_A | dA[10]; } if (param_values[id] < stored_param) { // if the new value is smaller heinz[id] = 0; dta_out_B = dta_out_B | dB[10]; } param_values[id] = stored_param; // use old parameter value } SEND_SERIAL(); } // ------------------------------------------------------------------------------------------------------ if (heinz[id] == 1) { // ------------------------------------------------------------------------------------------------------ PARAMETER_CONVERTER(id, C, ctrl_val_read[C]); // calculate new parameter value // C value is needed to control the LEDs corresponding with the control buttons // => value is stored in parameter_values[id], correct number of bits at the correct location // ------------------------------------------------------------------------------------------------------ if (C < 31 || (ctrl_val_read[C] == 1 && control[C] != rpatch)) { PARAM_DISPLAY(id); // generate and send sysex message for analog controls // generate and send sysex message for buttons that are pressed // don't generate and send sysex message for random patch sysexArray[5] = param_offsets[id]; // set parameter offset value sysexArray[6] = PARAMETER_MERGER(id); // set new parameter value SEND_SYSEX(); // send MIDI SysEx command } // ------------------------------------------------------------------------------------------------------ } ctrl_val_stored[C] = ctrl_val_read[C]; // overwrite stored value with new value // ctrl_val_stored & ctrl_val_read have values stores in order of controls } z++; // increase control number for next time } // ****************************************************************************************************** // * READ CONTROLS * // ------------------------------------------------------------------------------------------------------ // read value of control and store in ctrl_val_read // CTRL = Control to be read // 0~29 = pots // 31~33 = buttons void READ_CONTROL(int CTRL) { if (CTRL < 16) { byte mux_ctrl = CTRL; // read parameter controls 0~15 digitalWrite(mux_A, bitRead(mux_ctrl, 0)); // set mux bit 0 digitalWrite(mux_B, bitRead(mux_ctrl, 1)); // set mux bit 1 digitalWrite(mux_C, bitRead(mux_ctrl, 2)); // set mux bit 2 digitalWrite(mux_D, bitRead(mux_ctrl, 3)); // set mux bit 3 delay(2); ctrl_val_read[CTRL] = analogRead(ana_1) >> 4; // read analog value from parameter control, convert to 6 bits (0..63) and store // ------------------------------------------------------------------------------------------------------ } else if (CTRL < 30) { byte mux_ctrl = CTRL - 16; // read parameter controls 16~30 digitalWrite(mux_A, bitRead(mux_ctrl, 0)); // set mux bit 0 digitalWrite(mux_B, bitRead(mux_ctrl, 1)); // set mux bit 1 digitalWrite(mux_C, bitRead(mux_ctrl, 2)); // set mux bit 2 digitalWrite(mux_D, bitRead(mux_ctrl, 3)); // set mux bit 3 delay(2); ctrl_val_read[CTRL] = analogRead(ana_2) >> 4; // read analog value from parameter control, convert to 6 bits (0..63) and store // ------------------------------------------------------------------------------------------------------ } else if (CTRL == 31) { // read switch 1: chorus ctrl_val_read[31] = (digitalRead(SW1) ^1); } else if (CTRL == 32) { // read switch 2: VCF env polarity ctrl_val_read[32] = (digitalRead(SW2) ^1); } else if (CTRL == 33) { // read switch 3: random patch ctrl_val_read[33] = (digitalRead(SW3) ^1); } } // ****************************************************************************************************** // * PARAMETER CONVERTER * // ------------------------------------------------------------------------------------------------------ // convert ctrl_value_new[C] to correct number of bits and position, store in param_values[id] // param_id: id number // ctrl: control number // ctrl_value: read value from control // param_values[]: array with stored values for parameters in order of id number void PARAMETER_CONVERTER(byte param_id, byte ctrl, byte ctrl_value) { switch (param_id) { // ------------------------------------------------------------------------------------------------------ // Analog controls case OSC1_octave: // OSC1_octave: b6-b5 (0..2) case OSC2_octave: // OSC2_octave: b6-b5 (0..2) case VCF_kbd_track: // VCF_kbd_track: b6-b5 (0..2) ctrl_value = ctrl_value * (3.0 / 64.0); ctrl_value = ctrl_value << 5; // shift value to correct position break; case OSC1_waveform: // OSC1_waveform: b5-b3 (0..7) ctrl_value = ctrl_value / 8; // convert 6 bit value to 3 bits ctrl_value = ctrl_value << 3; // shift value to correct position break; case OSC2_waveform: // OSC2_waveform: b2-b0 (0..7) ctrl_value = ctrl_value / 8; // convert 6 bit value to 3 bits break; case OSC1_level: // OSC1_level: b4-b0 (0..31) case OSC2_level: // OSC2_level: b4-b0 (0..31) case noise_level: // noise_level: b4-b0 (0..31) case VCA_env_attack: // VCA_env_attack: b4-b0 (0..31) case VCA_env_decay: // VCA_env_decay: b4-b0 (0..31) case VCA_env_break: // VCA_env_break: b4-b0 (0..31) case VCA_env_slope: // VCA_env_slope: b4-b0 (0..31) case VCA_env_sustain: // VCA_env_sustain: b4-b0 (0..31) case VCA_env_release: // VCA_env_release: b4-b0 (0..31) case port_time: // port_time: b4-b0 (0..31) case VCF_env_int: // VCF_env_int: b4-b0 (0..31) case VCF_env_attack: // VCF_env_attack: b4-b0 (0..31) case VCF_env_decay: // VCF_env_decay: b4-b0 (0..31) case VCF_env_break: // VCF_env_break: b4-b0 (0..31) case VCF_env_slope: // VCF_env_slope: b4-b0 (0..31) case VCF_env_sustain: // VCF_env_sustain: b4-b0 (0..31) case VCF_env_release: // VCF_env_release: b4-b0 (0..31) case resonance: // resonance: b4-b0 (0..31) case mod_gen_freq: // mod_gen_freq: b4-b0 (0..31) case mod_gen_delay: // mod_gen_delay: b4-b0 (0..31) case mod_gen_OSC: // mod_gen_OSC: b4-b0 (0..31) case mod_gen_VCF: // mod_gen_VCF: b4-b0 (0..31) ctrl_value = ctrl_value / 2; // convert 7 bit value to 5 bits break; case OSC2_interval: // OSC2_interval: b5-b3 (0..5) ctrl_value = ctrl_value * (5.0 / 64.0); ctrl_value = ctrl_value << 3; // shift value to correct position break; case OSC2_detune: // OSC2_detune: b2-b0 (0..6) ctrl_value = ctrl_value * (7.0 / 64.0); break; case cutoff: // cutoff: b5-b0 (0..63) break; case bend_OSC: // bend_OSC: b3-b0 (0..12) ctrl_value = ctrl_value * (13.0 / 64.0); break; // ------------------------------------------------------------------------------------------------------ // buttons 1, 2 ,3 case bend_VCF: // id = 31 case VCF_env_polarity: // id = 32 case chorus: // id = 33 if (ctrl_value == 1) { ctrl_value = param_values[param_id] ^ B00100000; if (ctrl == 31) {digitalWrite(LED1, bitRead(ctrl_value, 5));} if (ctrl == 32) {digitalWrite(LED2, bitRead(ctrl_value, 5));} if (ctrl == 33) {digitalWrite(LED3, bitRead(ctrl_value, 5));} } else { ctrl_value = param_values[param_id]; } break; // ------------------------------------------------------------------------------------------------------ // random patcher // turn LED on while button assigned to random patcher is pressed case rpatch: // id = 40 if (ctrl_value == 1) { if (ctrl == 31) {digitalWrite(LED1, HIGH);} if (ctrl == 32) {digitalWrite(LED2, HIGH);} if (ctrl == 33) {digitalWrite(LED3, HIGH);} RANDOM_PATCHER(); } else { if (ctrl == 31) {digitalWrite(LED1, LOW);} if (ctrl == 32) {digitalWrite(LED2, LOW);} if (ctrl == 33) {digitalWrite(LED3, LOW);} dta_out_A = dA[11]; dta_out_B = dB[11]; SEND_SERIAL(); } break; // ------------------------------------------------------------------------------------------------------ // Assign mode has no hardware control but is used for factory presets case assign_mode: ctrl_value = ctrl_value * (3.0 / 64.0); ctrl_value = ctrl_value << 4; // shift value to correct position break; // ------------------------------------------------------------------------------------------------------ default: break; } param_values[param_id] = ctrl_value; // store new parameter value } // ****************************************************************************************************** // * PARAMETER MERGER * // ------------------------------------------------------------------------------------------------------ // merge parameters that share a byte and return result (merged_value) byte PARAMETER_MERGER(byte merge) { byte merged_value = 0; switch (merge) { case OSC1_octave: // 0. OSC1_octave: b6-b5 case VCA_env_release: // 29. VCA_env_release: b4-b0 merged_value = (param_values[OSC1_octave] | param_values[VCA_env_release]); break; case OSC1_waveform: // 1. OSC1_waveform: b5-b3 case OSC2_waveform: // 4. OSC2_waveform: b2-b0 merged_value = (param_values[OSC1_waveform] | param_values[OSC2_waveform]); break; case OSC2_octave: // 3. OSC2_octave: b6-b5 case mod_gen_freq: // 10. mod_gen_freq: b4-b0 merged_value = (param_values[OSC2_octave] | param_values[mod_gen_freq]); break; case OSC2_interval: // 6. OSC2_interval: b5-b3 case OSC2_detune: // 7. OSC2_detune: b2-b0 merged_value = (param_values[OSC2_interval] | param_values[OSC2_detune]); break; case mod_gen_delay: // 11. mod_gen_delay: b4-b0 case VCF_kbd_track: // 16. VCF_kbd_track: b6-b5 merged_value = (param_values[mod_gen_delay] | param_values[VCF_kbd_track]); break; case mod_gen_OSC: // 12. mod_gen_OSC: b4-b0 case VCF_env_polarity: // 32. VCF_env_polarity:b5 merged_value = (param_values[mod_gen_OSC] | param_values[VCF_env_polarity]); break; case mod_gen_VCF: // 13. mod_gen_VCF: b4-b0 case chorus: // 33. chorus: b5 merged_value = (param_values[mod_gen_VCF] | param_values[chorus]); break; case VCA_env_sustain: // 28. VCA_env_sustain: b4-b0 case bend_VCF: // 31. bend_VCF: b5 merged_value = (param_values[VCA_env_sustain] | param_values[bend_VCF]); break; case bend_OSC: // 30. bend_OSC: b3-b0 case assign_mode: // 34. assign_mode: b5-b4 merged_value = (param_values[bend_OSC] | param_values[assign_mode]); break; default: merged_value = (param_values[merge]); break; } return(merged_value); } // ****************************************************************************************************** // * RANDOM PATCH GENERATOR * // ------------------------------------------------------------------------------------------------------ void RANDOM_PATCHER() { for (id = 0; id <= 30; id++) { // create random values for parameters 0~30. PARAMETER_CONVERTER(id, 0, random(0, 64)); dta_out_A = random(0, 255); dta_out_B = random(0, 255); SEND_SERIAL(); delay(20); // PARAM_DISPLAY(id); // SEND_SERIAL(); // delay(35); // generate random value and convert to parameter value // C value is 0 (value doesn't matter) as LED values are not changed (only needed for controls > 30) // => value is stored in parameter_values[id], correct number of bits at the correct location // ------------------------------------------------------------------------------------------------------ if (id != 0 && id != 1 && id != 3 && id != 6 && id != 11) { // skip lowest id number parameters that share bytes sysexArray[5] = param_offsets[id]; // set parameter name sysexArray[6] = PARAMETER_MERGER(id); // set new param_value SEND_SYSEX(); // send MIDI message } // ------------------------------------------------------------------------------------------------------ } delay(350); } // ****************************************************************************************************** // * FACTORY PATCH LOADER * // ------------------------------------------------------------------------------------------------------ // converts factory patch values as written in the manual to values for the controller. // factory_presets is a 2D array with the factory parameter values. // factory_patch is a number corresponding with the selected patch. // pv is the value of the parameter as written in the list from the manual. // x is the parameter position in the list from the manual. (this is also the order in which values are stored in factory_presets) // the converted values are stored in param_values[] void LOAD_PRESETS(char factory_patch) { char pv = 0; for (byte x = 0; x <= 34; x++) { // x is parameter position in manual starting from 0 pv = factory_presets[factory_patch][x]; // read parameter value from factory patch switch (x) { case 0: // 0: OSC1_octave, parameter id = 0 if (pv == 16) {param_values[OSC1_octave] = B00000000;} if (pv == 8) {param_values[OSC1_octave] = B00100000;} if (pv == 4) {param_values[OSC1_octave] = B01000000;} break; case 1: // 1: OSC1_waveform, parameter id = 1 param_values[OSC1_waveform] = (pv - 1) << 3; break; case 2: // 2: OSC1_level, parameter id = 2 param_values[OSC1_level] = pv; id = OSC1_level; break; case 3: // 3: OSC2_octave, parameter id = 3 if (pv == 16) {param_values[OSC2_octave] = B00000000;} if (pv == 8) {param_values[OSC2_octave] = B00100000;} if (pv == 4) {param_values[OSC2_octave] = B01000000;} break; case 4: // 4: OSC2_waveform, parameter id = 4 param_values[OSC2_waveform] = pv - 1; param_value = param_values[OSC1_waveform] | param_values[OSC2_waveform]; id = OSC2_waveform; break; case 5: // 5: OSC2_level, parameter id = 5 param_values[OSC2_level] = pv; id = OSC2_level; break; case 6: // 6: OSC1_interval, parameter id = 6 if (pv == 1) {param_values[OSC2_interval] = B00000000;} if (pv == -3) {param_values[OSC2_interval] = B00001000;} if (pv == 3) {param_values[OSC2_interval] = B00010000;} if (pv == 4) {param_values[OSC2_interval] = B00011000;} if (pv == 5) {param_values[OSC2_interval] = B00100000;} break; case 7: // 7: OSC1_detune, parameter id = 7 param_values[OSC2_detune] = pv; param_value = param_values[OSC2_interval] | param_values[OSC2_detune]; id = OSC2_detune; break; case 8: // 8: noise_level, parameter id = 8 param_values[noise_level] = pv; id = noise_level; break; case 9: // 9: cutoff, parameter id = 14 param_values[cutoff] = pv; id = cutoff; break; case 10: // 10: resonance, parameter id = 15 param_values[resonance] = pv; id = resonance; break; case 11: // 11: VCF_kbd_track, parameter id = 16 param_values[VCF_kbd_track] = pv << 5; break; case 12: // 12: VCF_env_polarity, parameter id = 32 param_values[VCF_env_polarity] = (pv - 1) << 5; break; case 13: // 13: VCF_env_int, parameter id = 17 param_values[VCF_env_int] = pv; id = VCF_env_int; break; case 14: // 14: chorus, parameter id = 33 param_values[chorus] = pv << 5; break; case 15: // 15: VCF_env_attack, parameter id = 18 param_values[VCF_env_attack] = pv; id = VCF_env_attack; break; case 16: // 16: VCF_env_decay, parameter id = 19 param_values[VCF_env_decay] = pv; id = VCF_env_decay; break; case 17: // 17: VCF_env_break, parameter id = 20 param_values[VCF_env_break] = pv; id = VCF_env_break; break; case 18: // 18: VCF_env_slope, parameter id = 21 param_values[VCF_env_slope] = pv; id = VCF_env_slope; break; case 19: // 19: VCF_env_sustain, parameter id = 22 param_values[VCF_env_sustain] = pv; id = VCF_env_sustain; break; case 20: // 20: VCF_env_release, parameter id = 23 param_values[VCF_env_release] = pv; id = VCF_env_release; break; case 21: // 21: VCA_env_attack, parameter id = 24 param_values[VCA_env_attack] = pv; id = VCA_env_attack; break; case 22: // 22: VCA_env_decay, parameter id = 25 param_values[VCA_env_decay] = pv; id = VCA_env_decay; break; case 23: // 23: VCA_env_break, parameter id = 26 param_values[VCA_env_break] = pv; id = VCA_env_break; break; case 24: // 24: VCA_env_slope, parameter id = 27 param_values[VCA_env_slope] = pv; id = VCA_env_slope; break; case 25: // 25: VCA_env_sustain, parameter id 28 param_values[VCA_env_sustain] = pv; break; case 26: // 26: VCA_env_release, parameter id = 29 param_values[VCA_env_release] = pv; param_value = param_values[OSC1_octave] | param_values[VCA_env_release]; id = VCA_env_release; break; case 27: // 27: mod_gen_freq, parameter id = 10 param_values[mod_gen_freq] = pv; param_value = param_values[OSC2_octave] | param_values[mod_gen_freq]; id = mod_gen_freq; break; case 28: // 28: mod_gen_delay, parameter id = 11 param_values[mod_gen_delay] = pv; param_value = param_values[mod_gen_delay] | param_values[VCF_kbd_track]; id = mod_gen_delay; break; case 29: // 29: mod_gen_OSC, parameter id = 12 param_values[mod_gen_OSC] = pv; param_value = param_values[mod_gen_OSC] | param_values[VCF_env_polarity]; id = mod_gen_OSC; break; case 30: // 30: mod_gen_VCF, parameter id = 13 param_values[mod_gen_VCF] = pv; param_value = param_values[mod_gen_VCF] | param_values[chorus]; id = mod_gen_VCF; break; case 31: // 31: bend_OSC, parameter id = 30 param_values[bend_OSC] = pv; break; case 32: // 32: bend_VCF, parameter id = 31 param_values[bend_VCF] = pv << 5; param_value = param_values[bend_VCF] | param_values[VCA_env_sustain]; id = bend_VCF; break; case 33: // 33: port_time, parameter id = 9 param_values[port_time] = pv; id = port_time; break; case 34: // 34: assign_mode, parameter id = 34 param_values[assign_mode] = (pv - 1) << 4; param_value = param_values[assign_mode] | param_values[bend_OSC]; id = assign_mode; default: break; } // ------------------------------------------------------------------------------------------------------ // set parameter value for non shared parameters if (x == 2 || x == 5 || x == 8 || x == 9 || x == 10 || x == 13 || (x >= 15 && x <= 24) || x == 33) { param_value = pv; } // ------------------------------------------------------------------------------------------------------ // don't send first parameters with shared bytes to speed things up a bit if (x != 0 && x != 1 && x != 3 && x != 6 && x != 11 && x != 12 && x != 14 && x != 25 && x != 31) { sysexArray[5] = param_offsets[id]; // set parameter offset value sysexArray[6] = param_value; // set new parameter value SEND_SYSEX(); // send MIDI SysEx command } } // ------------------------------------------------------------------------------------------------------ digitalWrite(LED1, bitRead(param_values[control[31]], 5)); // turn LED1 on/off (0 = off, 1 = on) digitalWrite(LED2, bitRead(param_values[control[32]], 5)); // turn LED2 on/off (0 = off, 1 = on) digitalWrite(LED3, bitRead(param_values[control[33]], 5)); // turn LED3 on/off (0 = off, 1 = on) } // ****************************************************************************************************** // * PARAMETER DISPLAY * // ------------------------------------------------------------------------------------------------------ // converts param_values[id] to LED display data void PARAM_DISPLAY(byte idp) { byte dtA = 0; byte dtB = 0; switch(idp) { case 0: // OSC1_octave: 16/8/4 [b6~b5] case 3: // OSC2_octave: 16/8/4 [b6~b5] if (param_values[idp] == B00000000) {dtA = dA[1]; dtB = dB[6];} if (param_values[idp] == B00100000) {dtB = dB[8];} if (param_values[idp] == B01000000) {dtB = dB[4];} break; case 1: // OSC1_waveform: 1~8 [b5~b3] dtB = dB[(param_values[idp] >> 3) + 1]; break; case 4: // OSC2_waveform: 1~8 [b2~b0] dtB = dB[param_values[idp] + 1]; break; case 2: // OSC1_level: 0~31 case 5: // OSC2_level: 0~31 case 8: // noise_level: 0~31 case 9: // port_time: 0~31 case 10: // mod_gen_freq: 0~31 case 11: // mod_gen_delay: 0~31 case 12: // mod_gen_OSC: 0~31 case 13: // mod_gen_VCF: 0~31 case 15: // resonance: 0~31 case 17: // VCF_env_int: 0~31 case 18: // VCF_env_attack: 0~31 case 19: // VCF_env_decay: 0~31 case 20: // VCF_env_break: 0~31 case 21: // VCF_env_slope: 0~31 case 22: // VCF_env_sustain: 0~31 case 23: // VCF_env_release: 0~31 case 24: // VCA_env_attack: 0~31 case 25: // VCA_env_decay: 0~31 case 26: // VCA_env_break: 0~31 case 27: // VCA_env_slope: 0~31 case 28: // VCA_env_sustain: 0~31 case 29: // VCA_env_release: 0~31 if (param_values[idp] > 29) { dtA = dA[3]; dtB = dB[param_values[idp] - 30]; } else if (param_values[idp] > 19) { dtA = dA[2]; dtB = dB[param_values[idp] - 20]; } else if (param_values[idp] > 9) { dtA = dA[1]; dtB = dB[param_values[idp] - 10]; } else { dtB = dB[param_values[idp]]; } break; case 6: // OSC2_interval: 1/-3/3/4/5 [b5~b3] if (param_values[idp] == B00000000) {dtB = dB[1];} if (param_values[idp] == B00001000) {dtA = dA[11]; dtB = dB[3];} if (param_values[idp] == B00010000) {dtB = dB[3];} if (param_values[idp] == B00011000) {dtB = dB[4];} if (param_values[idp] == B00100000) {dtB = dB[5];} break; case 7: // OSC2_detune: 0~6 dtB = dB[param_values[idp]]; break; case 14: // cutoff: 0~63 if (param_values[idp] > 59) { dtA = dA[6]; dtB = dB[param_values[idp] - 60]; } else if (param_values[idp] > 49) { dtA = dA[5]; dtB = dB[param_values[idp] - 50]; } else if (param_values[idp] > 39) { dtA = dA[4]; dtB = dB[param_values[idp] - 40]; } else if (param_values[idp] > 29) { dtA = dA[3]; dtB = dB[param_values[idp] - 30]; } else if (param_values[idp] > 19) { dtA = dA[2]; dtB = dB[param_values[idp] - 20]; } else if (param_values[idp] > 9) { dtA = dA[1]; dtB = dB[param_values[idp] - 10]; } else { dtB = dB[param_values[idp]]; } break; case 16: // VCF_kbd_track: 0/1/2 [b6~b5] dtB = dB[param_values[idp] >> 5]; break; case 30: // bend_OSC: 0~12 if (param_values[idp] > 9) { dtA = dA[1]; dtB = dB[param_values[idp] - 10]; } else { dtB = dB[param_values[idp]]; } break; case 31: // bend_VCF: 0/1 [b5] case 33: // chorus: 0/1 [b5] dtB = dB[bitRead(param_values[idp], 5)]; break; case 32: // VCF_env_polarity: 1/2 [b5] dtB = dB[bitRead(param_values[idp], 5) + 1]; break; case 34: // assign_mode: 1/2/3 [b5~b4] dtB = dB[(param_values[idp] >> 4) + 1]; break; default: break; } dta_out_A = dtA; dta_out_B = dtB; SEND_SERIAL(); } // ****************************************************************************************************** // * SHOW START * // ------------------------------------------------------------------------------------------------------ // eye candy on startup void SHOW_START() { for (byte inhetrond = 0; inhetrond < 3; inhetrond++) { dta_out_A = B01000000; dta_out_B = B00000010; SEND_SERIAL(); delay(100); dta_out_A = B00000100; dta_out_B = B00100000; SEND_SERIAL(); delay(100); dta_out_A = B00000001; dta_out_B = B10000000; SEND_SERIAL(); delay(100); dta_out_A = B00001000; dta_out_B = B00010000; SEND_SERIAL(); delay(100); dta_out_A = B00100000; dta_out_B = B00000100; SEND_SERIAL(); delay(100); } dta_out_A = B10000000; dta_out_B = B00000001; SEND_SERIAL(); delay(100); dta_out_A = B00000010; dta_out_B = B01000000; SEND_SERIAL(); delay(100); } // ------------------------------------------------------------------------------------------------------ // END OF PROGRAM * // ******************************************************************************************************