diff --git a/.gitignore b/.gitignore index b578fdf..d0a5063 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ *.hex *.bak +*.csv +*.tsv +*.xml +fp-info-cache diff --git a/README.md b/README.md index 0cd8b0e..b27037e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,62 @@ # MIDI Drawbars Commander -## Notes: -You should use a Normally Open pedal to switch from the Leslie's speed, otherwise the "switch impulse" is sent on pedal release instead of pedal push (see issue #24) +## Pedals: +### Expression pedal +Any "standard" expression pedal compatible with the Roland EV5 will do. + +### Switch pedal (leslie speed) +You should use a Normally Open non latching (momentary) pedal to toggle the Leslie's speed, otherwise the "switch impulse" is sent on pedal release instead of pedal push (see issue #24) + +## SysEX implementation +Since v. 2.0 the device has a full set of custom System Exclusive messages that you can use to can configure what kind of commands/codes every button and drawbar sends. + +An editor is already available to configure the device. You can find it here: https://github.com/garubi/Web-editor-for-MIDI-Drawbars-Commander + +**Format for the requests:** + +`F0 X_MANID1 X_MANID2 X_PRODID X_REQ COOMAND vv F7` + +**Format for the reply:** + +`F0 X_MANID1 X_MANID2 X_PRODID X_REP OBJECT (Reply COdes) vv F7` + +**Manufacturer ID and Product ID** + +* `X_MANID1 = 0x37` // Manufacturer ID 1 +* `X_MANID2 = 0x72` // Manufacturer ID 2 +* `X_PRODID = 0x09` // Product ID + +**Where ACTION is:** +* `X_REQ = 0x00` // Request +* `X_REP = 0x01` // Replay + +**Where COMMAND is:** +* `X_FW_VER = 0x01` +// Firmware version. Replay vv is VERSION_MAJOR VERSION_MINOR VERSION_PATCH. +* `X_ACTIVE_PRESET = 0x02` // The active preset. Replay vv is (byte) Active preset id [0-3]. +* `X_CTRL_INFO = 0x03` // Reply with info about the controls: 1) Number of presets slots (PRESETS_COUNT), 2) Buttons number (BTN_COUNT), 3) Drawbars number (DRWB_COUNT) +* `X_REQ_CTRL_PARAMS = 0x10` // Current settings for a control: PRESET_ID CTRL_ID. Reply vv is: PRESET_ID CTRL_ID UPP_Type UPP_Prm UPP_Min UPP_Max UPP_Ch UPP_behavior LOW_Type LOW_Prm LOW_Min LOW_Max LOW_Ch LOW_behavior ALT_Type ALT_Prm ALT_Min ALT_Max ALT_Ch ALT_behavior +* `X_SET_CTRL_PARAMS = 0x11` // Send the settings for a control (but doesn't save it): PRESET_ID CTRL_ID UPP_Type UPP_Prm UPP_Min UPP_Max UPP_Ch UPP_behavior LOW_Type LOW_Prm LOW_Min LOW_Max LOW_Ch LOW_behavior ALT_Type ALT_Prm ALT_Min ALT_Max ALT_Ch ALT_behavior. Reply vv is 0 if is all right, an Error code if something went wrog +* `X_SET_PARAM = 0x12` //Send a setting for a single parameter (but doesn't save it): PRESET_ID CTRL_ID PARAM_ID (0-18) param value; +* `X_CMD_SAVE_PRESET= 0x7F` // Save the Preset to the non volative memory: vv is PRESET_ID. Reply vv is 0 if all went ok, an error code if someting wen wrong + +**REPLY CODES** +* `X_OK = 0x00` +* `X_ERROR = 0x7F` // Something went wrong. It will be followed by one of the following error codes + +**ERROR CODES** +* `X_ERROR_UNKNOWN = 0x7F` //127 +* `X_ERROR_PRESET = 0x10` //16 +* `X_ERROR_CONTROL = 0x20` //32 +* `X_ERROR_PARAM = 0x30` //48 + +## Factory restore +You can restore the presets factory defaults with the following procedure +- **turn off** the MIDI Drawbars Comamnder (i.e. detach from the USB cable) +- **press and hold the *ALT* button while turning on the Commander** (i.e. attach the USB cable). This will boot the Commander in *Reset mode*. The "*Leslie fast*" button's led will start blinking +- **while holding the *ALT* button, press the blinking "*Leslie fast*" button** to wipe the memory and reload the factory presets. The led will stop blink. +- **TODO: how to know when the restore finish?** +- Now **release the *ALT* button**: the Commander will exit from the *Reset mode* and it's ready to perform using the default parameters. ## Changelog: - v. 1.3.6 Fix issue with the Vibrato selector (isssue #70) diff --git a/Teensy/D9-drawbars-controller/D9-drawbars-controller.ino b/Teensy/D9-drawbars-controller/D9-drawbars-controller.ino index 439590e..57a18e4 100644 --- a/Teensy/D9-drawbars-controller/D9-drawbars-controller.ino +++ b/Teensy/D9-drawbars-controller/D9-drawbars-controller.ino @@ -1,7 +1,8 @@ /* D9 programmable drawbars controller - ver 1.3.7 + + ver 0.1.6 - sysex config Created 2018 By Stefano Garuti stefano@garuti.it @@ -17,17 +18,74 @@ /* TODO * reduce code repetition when controlling for IS_GLOBAL and IS_ALL in both analog and digital input * */ +const byte VERSION_MAJOR = 0; +const byte VERION_MINOR = 1; +const byte VERSION_PATCH = 6; #include +#include // https://github.com/jlesech/Eeprom24C32_64 #include #include // https://github.com/thomasfredericks/Bounce2/wiki #include #include #define PRINTSTREAM_FALLBACK -//S #define DEBUG_OUT Serial +//#define DEBUG_OUT Serial #include "Debug.hpp" // https://github.com/tttapa/Arduino-Debugging + +/* ************************************************************************ + * SysEX implementation + * + * Format for the requests : + * F0 X_MANID1 X_MANID2 X_PRODID X_REQ COOMAND vv F7 + * Format for the reply + * F0 X_MANID1 X_MANID2 X_PRODID X_REP OBJECT (Reply COdes) vv F7 + */ +const uint8_t X_MANID1 = 0x37; // Manufacturer ID 1 +const uint8_t X_MANID2 = 0x72; // Manufacturer ID 2 +const uint8_t X_PRODID = 0x09; // Product ID + +/* + * Where ACTION is + */ +const uint8_t X_REQ = 0x00; // Request +const uint8_t X_REP = 0x01; // Replay + + /* + * Where COMMAND is: + */ +const uint8_t X_FW_VER = 0x01; // Firmware version. Replay vv is VERSION_MAJOR VERSION_MINOR VERSION_PATCH. +const uint8_t X_ACTIVE_PRESET = 0x02; // The active preset. Replay vv is byte) Active preset id [0-3]. + +const uint8_t X_REQ_CTRL_PARAMS = 0x10; // Current settings for a control: PRESET_ID CTRL_ID. Reply vv is: PRESET_ID CTRL_ID UPP_Type UPP_Prm UPP_Min UPP_Max UPP_Ch UPP_behavior LOW_Type LOW_Prm LOW_Min LOW_Max LOW_Ch LOW_behavior ALT_Type ALT_Prm ALT_Min ALT_Max ALT_Ch ALT_behavior +const uint8_t X_SET_CTRL_PARAMS = 0x11; // Send the settings for a control (but doesn't save it): PRESET_ID CTRL_ID UPP_Type UPP_Prm UPP_Min UPP_Max UPP_Ch UPP_behavior LOW_Type LOW_Prm LOW_Min LOW_Max LOW_Ch LOW_behavior ALT_Type ALT_Prm ALT_Min ALT_Max ALT_Ch ALT_behavior. Reply vv is 0 if is all right, an Error code if something went wrog +const uint8_t X_SET_PARAM = 0x12; //Send a setting for a single parameter (but doesn't save it): PRESET_ID CTRL_ID PARAM_ID (0-18) param value; +const uint8_t X_CMD_SAVE_PRESET= 0x7F; // Save the Preset to the non volative memory: vv is PRESET_ID. Reply vv is 0 if all went ok, an error code if someting wen wrong + +/* + * REPLY CODES + */ + const uint8_t X_OK = 0x00; + const uint8_t X_ERROR = 0x7F; // Something went wrong + +/* + * ERROR CODES + */ + const uint8_t X_ERROR_UNKNOWN = 0x7F; //127 + const uint8_t X_ERROR_PRESET = 0x10; //16 + const uint8_t X_ERROR_CONTROL = 0x20; //32 + const uint8_t X_ERROR_PARAM = 0x30; //48 + +/* ************************************************************************ + * Instatiate the I2C eeprom + */ +#define EEPROM_ADDRESS 0x51 +static Eeprom24C32_64 eeprom(EEPROM_ADDRESS); +const word EEP_ACTIVE_PRST_ID_ADDR = 0; +const word EEP_PRSTS_START_ADDR = 10; // we let some byte free just in case we need to stroe other small pieces of global configuration... + + /* ************************************************************************* * Pins assign */ @@ -55,7 +113,7 @@ const byte LSL_STOP = 3; const byte LSL_FAST = 2; const byte LED_ALT = 0; -const byte BTN_COUNT = 8; // configurable digital input number (less the Alternate button, counted a part) include the pedal input +const byte BTN_COUNT = 8; // configurable digital input number (less the Alternate button, counted apart) include the pedal input const byte DRWB_COUNT = 10; // configurable number of drawbars used (add the exp pedal too) const byte CONTROLS_NUM = BTN_COUNT + DRWB_COUNT; const byte BTN_LED_COUNT = 7; // number of digital inputs that have leds (less the Alternate button, counted a part) @@ -84,24 +142,35 @@ const byte STATUSES_COUNT = sizeof(STATUS_IDX) / sizeof(STATUS_IDX[0]); const byte BTN_IDX_START = DRWB_COUNT; // at wich row of the presets array does the buttons rows starts? +/* Parameters position */ +const byte TYPE = 0; +const byte PARAM = 1; +const byte MIN = 2; +const byte MAX = 3; +const byte CHAN = 4; +const byte BEHAV = 5; +/* Parametes count */ +const byte PARAMS_NUM_PER_STATUS = 6; +const byte PARAMS_NUM_PER_CTRL = 6 * STATUSES_COUNT; + /* The multidimensional Array byte PRESETS will contains in each row: 1) the type of midi message to send out:*/ const byte TP_NO = 0; // Disabled const byte TP_CC = 1; // Control Change const byte TP_SX = 2; // System Exclusive - const byte TP_ON = 3; // Note on - const byte TP_PC = 4; // Program Change - + const byte TP_ON = 3; // Note on + const byte TP_PC = 4; // Program Change + /* 2) the command parameter (CC number, or Note number, or SySEx parameter etc...) 3) the min value to send out 4) the max value to sed out - 5) the button (and associated control command) behaviour: + 5) the button (and associated control command) behavior: */ const byte IS_GLOBAL = 1; // if the control sends always the same value both in Upper that in Lower state (sends what's set in the Upper one) const byte SEND_BOTH = 2; // send the value set in this STATUS to both the Upper and Lower channels - const byte IS_TOGGLE = 4; // is a pushbutton (momentary) or is toggle? + const byte IS_TOGGLE = 4; // is a pushbutton (momentary) or is toggle? /* We can set the Pedal Switch as an alias of another button (i.e. when we press the pedal, the script acts as we pressed the associated button: sends out the buttons values and turn on/off the respective LED ) @@ -115,9 +184,9 @@ const byte BTN_IDX_START = DRWB_COUNT; // at wich row of the presets array does * 0: Factory preset for Roland FA 06/07/07 * 1: Factory preset for GSi Gemini expander */ -const byte PRESETS[][CONTROLS_NUM][18]= +const byte PRESETS[][CONTROLS_NUM][PARAMS_NUM_PER_CTRL]= {// UPPER LOWER ALTERNATE -{//PIN Type Prm Min Max Ch Behaviour Type Prm Min Max Ch Behaviour Type Prm Min Max Ch Behaviour +{//PIN Type Prm Min Max Ch behavior Type Prm Min Max Ch behavior Type Prm Min Max Ch behavior /*DWB1*/ {TP_SX, 0x2A, 0, 8, 1, 0, TP_SX, 0x2A, 0, 8, 2, 0, TP_CC, 16, 0, 127, 0, SEND_BOTH}, // DRIVE /*DWB1_13*/ {TP_SX, 0x29, 0, 8, 1, 0, TP_SX, 0x29, 0, 8, 2, 0, TP_CC, 91, 0, 127, 0, SEND_BOTH}, //REV LEVEL /*DWB1_35*/ {TP_SX, 0x28, 0, 8, 1, 0, TP_SX, 0x28, 0, 8, 2, 0, TP_NO, 0x00, 0, 8, 1, 0}, // rev size @@ -137,7 +206,7 @@ const byte PRESETS[][CONTROLS_NUM][18]= /*LSL_FAST*/ {TP_CC, 80, 0, 127, 1, IS_TOGGLE + SEND_BOTH, TP_CC, 80, 0, 127, 2, IS_TOGGLE + SEND_BOTH, TP_NO, 0, 0, 127, 0, 0}, // Rev OFF /*PED_SWITCH*/ {TP_ON, 6, 0, 0, 0, IS_TOGGLE + SEND_BOTH, TP_ON, 0, 0, 0, 0, 0, TP_ON, 0, 0, 0, 0, 0}, },// UPPER LOWER ALTERNATE -{//PIN Type Prm Min Max Ch Behaviour Type Prm Min Max Ch Behaviour Type Prm Min Max Ch Behaviour +{//PIN Type Prm Min Max Ch behavior Type Prm Min Max Ch behavior Type Prm Min Max Ch behavior /*DWB1*/ {TP_CC, 20, 0, 127, 1, 0, TP_CC, 29, 0, 127, 1, 0, TP_CC, 76, 0, 127, 1, 0}, // DRIVE /*DWB1_13*/ {TP_CC, 19, 0, 127, 1, 0, TP_CC, 28, 0, 127, 1, 0, TP_CC, 84, 0, 127, 1, 0}, // REV LEVEL /*DWB1_35*/ {TP_CC, 18, 0, 127, 1, 0, TP_CC, 105, 0, 127, 1, 0, TP_CC, 83, 0, 127, 1, 0}, // REV SIZE @@ -159,31 +228,11 @@ const byte PRESETS[][CONTROLS_NUM][18]= } }; +byte preset[CONTROLS_NUM][PARAMS_NUM_PER_CTRL]={}; const byte PRESETS_COUNT = sizeof(PRESETS) / sizeof(PRESETS[0]); -/* Array index position labels */ -const byte TYPE = 0; -const byte PARAM = 1; -const byte MIN = 2; -const byte MAX = 3; -const byte CHAN = 4; -const byte BEHAV = 5; - -byte curr_preset; // the currennt selected preset. - -// declares the default status of buttons when we switch to a new preset -byte btn_default[BTN_LED_COUNT+1][STATUSES_COUNT] = { - //ALT UP LOW - /*PEDAL TO LOWER */ {1, 1, 0}, /*CHOVIB_ON*/ - /*preset */ {0, 1, 0}, /*PERC_ON*/ - /*preset */ {1, 0, 0}, /*PERC_SOFT*/ - /*preset */ {0, 0, 0}, /*PERC_FAST*/ - /*preset */ {0, 0, 1}, /*PERC_3RD*/ - /* leslie off */ {1, 0, 0}, /*LSL_STOP*/ - /* rev off */ {0, 1, 0}, /*LSL_FAST*/ - /* vib/cho sel. value*/ {127,0,0} // we start with C3 -}; - +byte curr_preset_id; // the currennt selected preset. +const int EEP_PARAMS_SPACE_SIZE = PRESETS_COUNT * CONTROLS_NUM * PARAMS_NUM_PER_CTRL; /* ************************************************************************* * Drawbars initialization @@ -230,18 +279,21 @@ const byte BTN_PRST_START = 1; // the btn at wich the preset selectors starts const byte BTN_PRST_COUNT = 4; // the number of presets selectors (even if inactive!!) const byte BTN_PED= 7; byte isPedalAliased; + /* ************************************************************************* * LEDs initialization */ // Controls LEDs attacched to MCP23017 Adafruit_MCP23017 led; -// An array that store the state of the buttons leds (including the Alt btn/led). -byte ledState[STATUSES_COUNT] = {}; + +byte ledState[STATUSES_COUNT] = {}; // An array that store the state of the buttons leds (including the Alt btn/led). byte ledState_old[STATUSES_COUNT] = {}; // the previous leds state, to check if we have to update the leds register long led_alt_on_time; + byte vibchoLedState; // stores the Vibrato/chorus leds state byte vibchoLedState_old; // the previous leds state, to check if we have to update the leds register + byte old_preset_led; // the previous selected preset's led byte vibcho_led_on_old; long led_midi_on_time; @@ -257,6 +309,9 @@ void setup() Serial.begin(38400); MIDI.begin(MIDI_CHANNEL_OMNI); + // Initialize EEPROM library. + eeprom.initialize(); + // set ALT button as input Pullup and attach debouncer pinMode(BTN_ALT, INPUT_PULLUP); btn_alt.attach(BTN_ALT); @@ -290,15 +345,93 @@ void setup() OLD_STATUS = ST_LOW; btnAlt_released = 1; - // load the default preset - for (byte btn_scanned = BTN_PRST_START; btn_scanned < (BTN_PRST_COUNT + BTN_PRST_START); btn_scanned++) { - if( 0 != btn_default[btn_scanned][BTN_PRST_STATUS] ){ - changePreset( btn_scanned ); - break; - } + // To reset to factory presets keep pressed the ALT button while turning on the device + // then press the "leslie fast" button (the last one on the right) + btn_alt.update(); + long reset_btn_on_time = millis(); + byte reset_btn_led = 1; + byte im_resetting = false; + + int counter = 0; + //byte parameter[EEP_PARAMS_SPACE_SIZE] = {}; + + while (btn_alt.read() == 0){ + led.digitalWrite(0, 1); // turn on the ALT_BTN + + //now blink btn[6] + if( millis()-reset_btn_on_time > 200 && !im_resetting ){ + led.digitalWrite(7, !reset_btn_led); + reset_btn_led = !reset_btn_led; + reset_btn_on_time = millis(); } + btn_alt.update(); // does the ALT button chaged? + btn[6].update(); // does the Reset button changed? + + if (btn[6].fell()){ // the reset button was pressed: let's start the reset procedure + //DEBUGFN("factory restore should go here"); + led.digitalWrite(7, HIGH); //keep the led on to signal that the reset procedure is starting + im_resetting = true; //don't blink animore + + for(byte prs = 0; prs < PRESETS_COUNT; prs++){ + for (byte st = 0; st < CONTROLS_NUM; st++){ + for (byte te = 0; te < PARAMS_NUM_PER_CTRL; te++) { + //parameter[counter] = PRESETS[prs][st][te]; + eeprom.writeByte(EEP_PRSTS_START_ADDR + counter, PRESETS[prs][st][te]); + //NAMEDVALUE(EEP_PRSTS_START_ADDR + counter) + //NAMEDVALUE(PRESETS[prs][st][te]) + counter++; + } + } + } + + + // turn the led off when the write procedure finish + led.digitalWrite(7, LOW); + + } + + btn_alt.update(); // does the ALT button chaged? + btn[6].update(); // does the Reset button changed? + + if (btn[6].fell()){ // the reset button was pressed: let's start the reset procedure + //DEBUGFN("factory restore should go here"); + led.digitalWrite(7, HIGH); //keep the led on to signal that the reset procedure is starting + im_resetting = true; //don't blink animore + + + + /* ************************************** + * TODO: Write the presets to the eprom + * 1: read the hardcoded presets + * 2: put them on the eeprom + */ + for(byte prs = 0; prs < PRESETS_COUNT; prs++){ + for (byte st = 0; st < CONTROLS_NUM; st++){ + for (byte te = 0; te < PARAMS_NUM_PER_CTRL; te++) { + //parameter[counter] = PRESETS[prs][st][te]; + eeprom.writeByte(EEP_PRSTS_START_ADDR + counter, PRESETS[prs][st][te]); + //NAMEDVALUE(EEP_PRSTS_START_ADDR + counter) + //NAMEDVALUE(PRESETS[prs][st][te]) + counter++; + } + } + } + // write it + //eeprom.writeBytes(EEP_PRSTS_START_ADDR, EEP_PARAMS_SPACE_SIZE, parameter); + + // turn the led off when the write procedure finish + led.digitalWrite(7, LOW); + //im_resetting = true; //don't blink animore + } + } + + curr_preset_id = eep_read_curr_preset_id(); // load the last used preset from memory. + load_preset( curr_preset_id ); + syncAnalogData(); + + } void loop() { @@ -321,67 +454,44 @@ void loop() { } -bool isPresetButton( byte btn_scanned, byte the_status ) { - if( the_status == BTN_PRST_STATUS && (btn_scanned >= BTN_PRST_START && btn_scanned <= (BTN_PRST_COUNT + BTN_PRST_START -1) ) ){ - return true; - } - return false; -} - -void changePreset( byte btn_scanned ){ - DEBUGFN(NAMEDVALUE(btn_scanned)); - // set it only if is defined in the preset array - if( btn_scanned - BTN_PRST_START <= PRESETS_COUNT - 1){ - DEBUGFN("CHANGING preset"); - setBtnLedState(BTN_PRST_STATUS, old_preset_led, 0); - setBtnLedState(BTN_PRST_STATUS, btn_scanned, !btn_state[BTN_PRST_STATUS][btn_scanned]); - - // set the new preset value - curr_preset = btn_scanned - BTN_PRST_START; +void load_preset( byte preset_id ){ + byte btn_scanned = preset_id + BTN_PRST_START; + DEBUGFN(NAMEDVALUE(btn_scanned)); + setBtnLedState(BTN_PRST_STATUS, old_preset_led, 0); + setBtnLedState(BTN_PRST_STATUS, btn_scanned, !btn_state[BTN_PRST_STATUS][btn_scanned]); + + // reset all data + DEBUGFN("Reset btns and leds data"); + // SET al buttons to 0 + for (byte st = 0; st < STATUSES_COUNT; st++){ + for (byte btn_scanned = 0; btn_scanned < BTN_LED_COUNT; btn_scanned++) { + if ( !isPresetButton(btn_scanned, st) ){ // check that's not a Preset button + updateBtn( btn_scanned, 0, st ); + } + } + } + // setVibchoType( btn_default[7][ST_ALT] ); - // reset all data - resetToDefaultData(); + eep_load_preset_params( preset_id ); // Load the preset's parameters - // Check if the pedal is aliased - if( PRESETS[curr_preset][BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + MIN ] == 0 && PRESETS[curr_preset][BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + MAX ] == 0 && PRESETS[curr_preset][BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + CHAN ] == 0){ - isPedalAliased = true; - } - else { - isPedalAliased = false; - } - DEBUGFN(NAMEDVALUE(isPedalAliased)); - DEBUGFN( NAMEDVALUE(curr_preset) ); - old_preset_led = btn_scanned; - } - else{ - DEBUGFN("CAN'T CHANGE preset: preset location empty"); - } + //NAMEDVALUE(preset); + // Check if the pedal is aliased + if( preset[BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + MIN ] == 0 && preset[BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + MAX ] == 0 && preset[BTN_PED+BTN_IDX_START][STATUS_IDX[ST_UP] + CHAN ] == 0){ + isPedalAliased = true; + } + else { + isPedalAliased = false; + } + DEBUGFN( NAMEDVALUE( isPedalAliased ) ); + old_preset_led = btn_scanned; } -void resetToDefaultData(){ - DEBUGFN("Reset to default data"); - // SET al buttons to 0 - for (byte st = 0; st < STATUSES_COUNT; st++){ - for (byte btn_scanned = 0; btn_scanned < BTN_LED_COUNT; btn_scanned++) { - if ( !isPresetButton(btn_scanned, st) ){ // check that's not a Preset button - updateBtn( btn_scanned, 0, st ); - } - } - } - - //Set the default value for all buttons, only if it's not 0 (since we have already set all of them to 0) - for (byte st = 0; st < STATUSES_COUNT; st++){ - for (byte btn_scanned = 0; btn_scanned < BTN_LED_COUNT; btn_scanned++) { - if ( !isPresetButton(btn_scanned, st) ){ // check that's not a Preset button - if (btn_default[btn_scanned][st] != 0 ){ - updateBtn( btn_scanned, btn_default[btn_scanned][st], st ); - } - } - } +bool isPresetButton( byte btn_scanned, byte the_status ) { + if( the_status == BTN_PRST_STATUS && (btn_scanned >= BTN_PRST_START && btn_scanned <= (BTN_PRST_COUNT + BTN_PRST_START -1) ) ){ + return true; } - - setVibchoType( btn_default[7][ST_ALT] ); + return false; } void getAltBtn(){ @@ -505,7 +615,7 @@ void setVibchoType( byte CCvalue ){ vibchoLedState = 0; // reset the leds bitWrite(vibchoLedState, vibcho_led_on, 1 ); } - sendMidi( PRESETS[curr_preset][VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +TYPE], PRESETS[curr_preset][VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +PARAM], CCvalue, VIBCHO_SEL_DRWB, PRESETS[curr_preset][VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +CHAN] ); + sendMidi( preset[VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +TYPE], preset[VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +PARAM], CCvalue, VIBCHO_SEL_DRWB, preset[VIBCHO_SEL_DRWB][STATUS_IDX[VIBCHO_SEL_STATUS] +CHAN] ); } @@ -513,18 +623,18 @@ void getAnalogData() { for (int drwb_scanned = 0; drwb_scanned < DRWB_COUNT; drwb_scanned++) { // update the ResponsiveAnalogRead object every loop drwb[drwb_scanned].update(); - if( PRESETS[curr_preset][drwb_scanned][STATUS_IDX[STATUS] +TYPE] != TP_NO ){ + if( preset[drwb_scanned][STATUS_IDX[STATUS] +TYPE] != TP_NO ){ // if the repsonsive value has changed, go if (drwb[drwb_scanned].hasChanged()) { analogData[drwb_scanned] = drwb[drwb_scanned].getValue() >> 3; if (analogData[drwb_scanned] != analogDataLag[drwb_scanned]) { analogDataLag[drwb_scanned] = analogData[drwb_scanned]; - DEBUGFN( "DWB changed: " ); - DEBUGVAL(drwb_scanned,analogData[drwb_scanned]); + //DEBUGFN( "DWB changed: " ); + //DEBUGVAL(drwb_scanned,analogData[drwb_scanned]); // check if this drawbar is dedicated to the VIB/CHO control if ( STATUS == VIBCHO_SEL_STATUS && drwb_scanned == VIBCHO_SEL_DRWB ){ - DEBUGFN("This DWB controls VIBCHO selection"); + //DEBUGFN("This DWB controls VIBCHO selection"); setVibchoType( analogData[drwb_scanned] ); } else{ @@ -541,7 +651,7 @@ void syncAnalogData() { for (int drwb_scanned = 0; drwb_scanned < DRWB_COUNT; drwb_scanned++) { // update the ResponsiveAnalogRead object every loop drwb[drwb_scanned].update(); - if( PRESETS[curr_preset][drwb_scanned][STATUS_IDX[STATUS] +TYPE] != TP_NO ){ + if( preset[drwb_scanned][STATUS_IDX[STATUS] +TYPE] != TP_NO ){ analogData[drwb_scanned] = drwb[drwb_scanned].getValue() >> 3; analogDataLag[drwb_scanned] = analogData[drwb_scanned]; DEBUGFN( "DWB synced: " ); @@ -554,23 +664,23 @@ void syncAnalogData() { } void sendAnalogMidi ( byte value, byte control, byte curr_status ){ - if ( ( PRESETS[curr_preset][control][STATUS_IDX[curr_status] +BEHAV] & SEND_BOTH ) == SEND_BOTH ){ - sendMidi( PRESETS[curr_preset][control][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][control][STATUS_IDX[curr_status] +PARAM], value, control, PRESETS[curr_preset][control][STATUS_IDX[ST_UP] +CHAN] ); - sendMidi( PRESETS[curr_preset][control][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][control][STATUS_IDX[curr_status] +PARAM], value, control, PRESETS[curr_preset][control][STATUS_IDX[ST_LOW] +CHAN] ); + if ( ( preset[control][STATUS_IDX[curr_status] +BEHAV] & SEND_BOTH ) == SEND_BOTH ){ + sendMidi( preset[control][STATUS_IDX[curr_status] +TYPE], preset[control][STATUS_IDX[curr_status] +PARAM], value, control, preset[control][STATUS_IDX[ST_UP] +CHAN] ); + sendMidi( preset[control][STATUS_IDX[curr_status] +TYPE], preset[control][STATUS_IDX[curr_status] +PARAM], value, control, preset[control][STATUS_IDX[ST_LOW] +CHAN] ); } - else if ( ( PRESETS[curr_preset][control][STATUS_IDX[curr_status] +BEHAV] & IS_GLOBAL ) == IS_GLOBAL ) { - sendMidi( PRESETS[curr_preset][control][STATUS_IDX[ST_UP] +TYPE], PRESETS[curr_preset][control][STATUS_IDX[ST_UP] +PARAM], value, control, PRESETS[curr_preset][control][STATUS_IDX[ST_UP] +CHAN] ); + else if ( ( preset[control][STATUS_IDX[curr_status] +BEHAV] & IS_GLOBAL ) == IS_GLOBAL ) { + sendMidi( preset[control][STATUS_IDX[ST_UP] +TYPE], preset[control][STATUS_IDX[ST_UP] +PARAM], value, control, preset[control][STATUS_IDX[ST_UP] +CHAN] ); } else { - sendMidi( PRESETS[curr_preset][control][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][control][STATUS_IDX[curr_status] +PARAM], value, control, PRESETS[curr_preset][control][STATUS_IDX[curr_status] +CHAN] ); + sendMidi( preset[control][STATUS_IDX[curr_status] +TYPE], preset[control][STATUS_IDX[curr_status] +PARAM], value, control, preset[control][STATUS_IDX[curr_status] +CHAN] ); } } void updateBtn( byte btn_scanned, byte btn_val, byte curr_status ){ byte btn_index = btn_scanned + BTN_IDX_START; - if ( ( PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +BEHAV] & SEND_BOTH ) == SEND_BOTH ){ - sendMidi( PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, PRESETS[curr_preset][btn_index][STATUS_IDX[ST_UP] +CHAN] ); - sendMidi( PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, PRESETS[curr_preset][btn_index][STATUS_IDX[ST_LOW] +CHAN] ); + if ( ( preset[btn_index][STATUS_IDX[curr_status] +BEHAV] & SEND_BOTH ) == SEND_BOTH ){ + sendMidi( preset[btn_index][STATUS_IDX[curr_status] +TYPE], preset[btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, preset[btn_index][STATUS_IDX[ST_UP] +CHAN] ); + sendMidi( preset[btn_index][STATUS_IDX[curr_status] +TYPE], preset[btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, preset[btn_index][STATUS_IDX[ST_LOW] +CHAN] ); if( curr_status == ST_ALT ){ setBtnLedState(curr_status, btn_scanned, btn_val); btn_state[curr_status][btn_scanned] = btn_val; @@ -583,15 +693,15 @@ void updateBtn( byte btn_scanned, byte btn_val, byte curr_status ){ } } - else if ( ( PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +BEHAV] & IS_GLOBAL ) == IS_GLOBAL ) { - sendMidi( PRESETS[curr_preset][btn_index][STATUS_IDX[ST_UP] +TYPE], PRESETS[curr_preset][btn_index][STATUS_IDX[ST_UP] +PARAM], btn_val * 127, btn_index, PRESETS[curr_preset][btn_index][STATUS_IDX[ST_UP] +CHAN] ); + else if ( ( preset[btn_index][STATUS_IDX[curr_status] +BEHAV] & IS_GLOBAL ) == IS_GLOBAL ) { + sendMidi( preset[btn_index][STATUS_IDX[ST_UP] +TYPE], preset[btn_index][STATUS_IDX[ST_UP] +PARAM], btn_val * 127, btn_index, preset[btn_index][STATUS_IDX[ST_UP] +CHAN] ); setBtnLedState(ST_UP, btn_scanned, btn_val); setBtnLedState(ST_LOW, btn_scanned, btn_val); btn_state[ST_UP][btn_scanned] = btn_val; btn_state[ST_LOW][btn_scanned] = btn_val; } else { - sendMidi( PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +TYPE], PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, PRESETS[curr_preset][btn_index][STATUS_IDX[curr_status] +CHAN] ); + sendMidi( preset[btn_index][STATUS_IDX[curr_status] +TYPE], preset[btn_index][STATUS_IDX[curr_status] +PARAM], btn_val * 127, btn_index, preset[btn_index][STATUS_IDX[curr_status] +CHAN] ); setBtnLedState(curr_status, btn_scanned, btn_val); btn_state[curr_status][btn_scanned] = btn_val; } @@ -615,22 +725,35 @@ void getDigitalData() { if (btn[btn_scanned].fell()) { //se il pulsante è un preset... if(isPresetButton( btn_scanned, STATUS )) { - changePreset( btn_scanned ); + byte preset_id = btn_scanned - BTN_PRST_START; + if( preset_id != curr_preset_id && preset_id <= PRESETS_COUNT - 1){ // change preset only if the new one is different from the previous ande if is defined in the preset array + DEBUGFN("CHANGING preset"); + load_preset( preset_id ); + // set the new preset id value + curr_preset_id = preset_id; + // save it in memory + eep_store_curr_preset_id(); + DEBUGFN( NAMEDVALUE(curr_preset_id) ); + } + else{ + DEBUGFN("CAN'T CHANGE preset: preset location empty"); + } } else{ if( btnAlt_pushed == 0){ - if ( PRESETS[curr_preset][btn_index][STATUS_IDX[STATUS] + TYPE] != TP_NO ){ + if ( preset[btn_index][STATUS_IDX[STATUS] + TYPE] != TP_NO ){ // Caso "normale" il pulsante è premuto da solo DEBUGFN("BTN pressed / value: "); DEBUGVAL(btn_scanned, btn_val); // if the Pedal is aliased, we use the settings of the relative button if( isPedalAliased == true && btn_scanned == BTN_PED ){ - btn_scanned = PRESETS[curr_preset][btn_index][STATUS_IDX[ST_UP] + PARAM]; + btn_scanned = preset[btn_index][STATUS_IDX[ST_UP] + PARAM]; btn_index = btn_scanned + BTN_IDX_START; } - if ( (PRESETS[curr_preset][btn_index][STATUS_IDX[STATUS] +BEHAV] & IS_TOGGLE )== IS_TOGGLE){ + + if ( (preset[btn_index][STATUS_IDX[STATUS] +BEHAV] & IS_TOGGLE )== IS_TOGGLE){ DEBUGFN("toggle..."); // il pulsante è TOGGLE btn_val = !btn_state[STATUS][btn_scanned]; @@ -667,14 +790,15 @@ void getDigitalData() { // Pulsante rilasciato else { // reagisce solo se questo pulsante non è TOGGLE e non è PRESET - if ( !isPresetButton( btn_scanned, STATUS ) && PRESETS[curr_preset][btn_index][STATUS_IDX[STATUS] + TYPE] != TP_NO ){ + if ( !isPresetButton( btn_scanned, STATUS ) && preset[btn_index][STATUS_IDX[STATUS] + TYPE] != TP_NO ){ // if the Pedal is aliased, we use the settings of the relative button if( isPedalAliased == true && btn_scanned == BTN_PED ){ - btn_scanned = PRESETS[curr_preset][btn_index][STATUS_IDX[STATUS] + PARAM]; + btn_scanned = preset[btn_index][STATUS_IDX[STATUS] + PARAM]; btn_index = btn_scanned + BTN_IDX_START; } - if ( (PRESETS[curr_preset][btn_index][STATUS_IDX[STATUS] +BEHAV] & IS_TOGGLE) != IS_TOGGLE){ + + if ( (preset[btn_index][STATUS_IDX[STATUS] +BEHAV] & IS_TOGGLE) != IS_TOGGLE){ DEBUGFN("Btn released - No TOOGLE & No PRESET..."); DEBUGVAL(!btn_val); //if is_pedal && pedalAlias > 0 --> btn_scanned = pedalAlias, btn_index = btn_scanned + BTN_IDX_START @@ -689,8 +813,8 @@ void getDigitalData() { void sendMidi( int type, byte parameter, byte value, byte control, byte channel) { - DEBUGFN("Send midi"); - DEBUGVAL(type,parameter,value,control); + //DEBUGFN("Send midi"); + //DEBUGVAL(type,parameter,value,control); int SysexLenght = 0; switch (type) { case TP_ON: // Note On @@ -710,7 +834,7 @@ void sendMidi( int type, byte parameter, byte value, byte control, byte channel) usbMIDI.sendProgramChange(value, channel); break; case TP_SX: // SysEx - if (curr_preset == 0) { + if (curr_preset_id == 0) { /** * è il preset per Roland FA 06/07/08 */ @@ -724,8 +848,8 @@ void sendMidi( int type, byte parameter, byte value, byte control, byte channel) data[8] = partsB[channel - 1]; data[10] = parameter; data[11] = value; - if ( PRESETS[curr_preset][control][STATUS_IDX[STATUS] +MAX] != 127 || PRESETS[curr_preset][control][STATUS_IDX[STATUS] +MIN] != 0 ) { - data[11] = map(value, 0, 127, PRESETS[curr_preset][control][STATUS_IDX[STATUS] +MIN], PRESETS[curr_preset][control][STATUS_IDX[STATUS] +MAX]); + if ( preset[control][STATUS_IDX[STATUS] +MAX] != 127 || preset[control][STATUS_IDX[STATUS] +MIN] != 0 ) { + data[11] = map(value, 0, 127, preset[control][STATUS_IDX[STATUS] +MIN], preset[control][STATUS_IDX[STATUS] +MAX]); } /* @@ -810,9 +934,136 @@ void MidiMerge(){ midi::MidiType mtype = (midi::MidiType)type; MIDI.send(mtype, data1, data2, channel); } else { - // SysEx messages are special. The message length is given in data1 & data2 - unsigned int SysExLength = data1 + data2 * 256; - MIDI.sendSysEx(SysExLength, usbMIDI.getSysExArray(), true); + // we received SysEx + uint8_t* sysex_message = usbMIDI.getSysExArray(); + + if ( sysex_message[1] == X_MANID1 && sysex_message[2] == X_MANID2 && sysex_message[3] == X_PRODID && sysex_message[4] == X_REQ){ + // The SysEx is for internal use of Drawbar Commander + DEBUGFN("SYSEX for us ;-) "); + DEBUGVAL(sysex_message[5]) ; + switch( sysex_message[5]){ + case X_FW_VER: // request version + { + uint8_t rp[9] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_FW_VER, X_OK, VERSION_MAJOR, VERION_MINOR, VERSION_PATCH }; + usbMIDI.sendSysEx(9, rp, false); + } + break; + case X_ACTIVE_PRESET: // request active preset + { + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_ACTIVE_PRESET, X_OK, curr_preset_id }; + usbMIDI.sendSysEx(7, rp, false); + } + break; + case X_REQ_CTRL_PARAMS: // request the parameter for a control + { + byte preset_id = sysex_message[6]; + byte control_id = sysex_message[7]; + + if( preset_id != curr_preset_id ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_REQ_CTRL_PARAMS, X_ERROR, X_ERROR_PRESET }; + usbMIDI.sendSysEx(7, rp, false); + } + else if(control_id > CONTROLS_NUM -1 ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_REQ_CTRL_PARAMS, X_ERROR, X_ERROR_CONTROL }; + usbMIDI.sendSysEx(7, rp, false); + } + else{ + uint8_t rp[8+PARAMS_NUM_PER_CTRL] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_REQ_CTRL_PARAMS, X_OK, preset_id, control_id}; + + int single_param_space_size = CONTROLS_NUM * PARAMS_NUM_PER_CTRL; + int address = EEP_PRSTS_START_ADDR + (preset_id * single_param_space_size) + (control_id * PARAMS_NUM_PER_CTRL); + + for (byte te = 0; te <= PARAMS_NUM_PER_CTRL; te++) { + rp[8+te] = eeprom.readByte( address + te ); + } + + usbMIDI.sendSysEx(8 + PARAMS_NUM_PER_CTRL, rp, false); + } + } + break; + case X_SET_CTRL_PARAMS: // set the parameters for a control + // PRESET_ID CTRL_ID UPP_Type UPP_Prm UPP_Min UPP_Max UPP_Ch UPP_behavior LOW_Type LOW_Prm LOW_Min LOW_Max LOW_Ch LOW_behavior ALT_Type ALT_Prm ALT_Min ALT_Max ALT_Ch ALT_behavior. Reply vv is 0 if is all right, an Error code if something went wrog + { + //TODO: validate the inputs + byte preset_id = sysex_message[6]; + byte control_id = sysex_message[7]; + if( preset_id != curr_preset_id ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_CTRL_PARAMS, X_ERROR, X_ERROR_PRESET }; + usbMIDI.sendSysEx(7, rp, false); + } + else if(control_id > CONTROLS_NUM -1 ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_CTRL_PARAMS, X_ERROR, X_ERROR_CONTROL }; + usbMIDI.sendSysEx(7, rp, false); + } + else{ + + for (byte pr = 8; pr <= PARAMS_NUM_PER_CTRL+8; pr++) { + preset[control_id][pr] = sysex_message[pr]; + } + + //reply + uint8_t rp[8+PARAMS_NUM_PER_CTRL] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_CTRL_PARAMS, X_OK, preset_id, control_id}; + for (byte te = 0; te <= PARAMS_NUM_PER_CTRL; te++) { + rp[8+te] = preset[control_id][te]; + } + usbMIDI.sendSysEx(8 + PARAMS_NUM_PER_CTRL, rp, false); + } + + } + break; + case X_SET_PARAM: + // PRESET_ID CTRL_ID PARAM_ID (0-18) param value; + { + DEBUGVAL(PARAMS_NUM_PER_CTRL); + byte preset_id = sysex_message[6]; + byte control_id = sysex_message[7]; + byte param_id = sysex_message[8]; + byte param_value = sysex_message[9]; + DEBUGVAL(param_id); + if( preset_id != curr_preset_id ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_PARAM, X_ERROR, X_ERROR_PRESET }; + usbMIDI.sendSysEx(7, rp, false); + } + else if(control_id > CONTROLS_NUM -1 ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_PARAM, X_ERROR, X_ERROR_CONTROL }; + usbMIDI.sendSysEx(7, rp, false); + } + else if( param_id > PARAMS_NUM_PER_CTRL -1 ){ + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_PARAM, X_ERROR, X_ERROR_PARAM }; + + usbMIDI.sendSysEx(7, rp, false); + } + else{ + + //TODO: Validate param_value + preset[control_id][param_id] = param_value; + uint8_t rp[10] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_SET_PARAM, X_OK, preset_id, control_id, param_id, param_value }; + usbMIDI.sendSysEx(10, rp, false); + } + } + break; + case X_CMD_SAVE_PRESET: // save current preset + { + byte preset_id = sysex_message[6]; + + if( preset_id != curr_preset_id ){ // if it's not for the current preset raise an error + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_CMD_SAVE_PRESET, X_ERROR, X_ERROR_PRESET }; + usbMIDI.sendSysEx(7, rp, false); + } + else{ + eep_write_preset_params(preset_id); + uint8_t rp[7] = { X_MANID1, X_MANID2, X_PRODID, X_REP, X_CMD_SAVE_PRESET, X_OK, preset_id }; + usbMIDI.sendSysEx(7, rp, false); + } + } + break; + } + } + else{ + // SysEx messages are special. The message length is given in data1 & data2 + unsigned int SysExLength = data1 + data2 * 256; + MIDI.sendSysEx(SysExLength, usbMIDI.getSysExArray(), true); + } } //DEBUGFN( NAMEDVALUE(type) ); if (type != usbMIDI.ActiveSensing && type != 255) { @@ -823,21 +1074,62 @@ void MidiMerge(){ if (STATUS == BTN_PRST_STATUS) { - byte midiLedStatus = bitRead(ledState[BTN_PRST_STATUS], BTN_PRST_START + 1 + curr_preset ); + byte midiLedStatus = bitRead(ledState[BTN_PRST_STATUS], BTN_PRST_START + 1 + curr_preset_id ); //DEBUGFN( NAMEDVALUE(midiLedStatus) ); if (midiLedStatus != 0 && midi_activity ){ - setBtnLedState(BTN_PRST_STATUS, BTN_PRST_START + curr_preset, 0); + setBtnLedState(BTN_PRST_STATUS, BTN_PRST_START + curr_preset_id, 0); led_midi_on_time = millis(); // midi_activity = false; } if( (millis()-led_midi_on_time > 100) && (midiLedStatus == 0) ){ - // digitalWriteFast(BTN_PRST_START + 1 + curr_preset, 1); + // digitalWriteFast(BTN_PRST_START + 1 + curr_preset_id, 1); // DEBUGFN( "activity off" ); - setBtnLedState(BTN_PRST_STATUS, BTN_PRST_START + curr_preset, 1); + setBtnLedState(BTN_PRST_STATUS, BTN_PRST_START + curr_preset_id, 1); } } +} + +// Return a byte with the last active preset +byte eep_read_curr_preset_id(){ + // Read a byte at address 0 in EEPROM memory. + byte data = eeprom.readByte(EEP_ACTIVE_PRST_ID_ADDR); + DEBUGFN(NAMEDVALUE(data)); + return data; + } + +void eep_store_curr_preset_id(){ + // Write a byte in EEPROM memory. + DEBUGFN(NAMEDVALUE(curr_preset_id)); + eeprom.writeByte(EEP_ACTIVE_PRST_ID_ADDR, curr_preset_id); + delay(10); + } + +void eep_load_preset_params( byte preset_id ){ + + int single_param_space_size = CONTROLS_NUM * PARAMS_NUM_PER_CTRL; + int address = EEP_PRSTS_START_ADDR + (preset_id * single_param_space_size); + int counter = 0; + for (byte st = 0; st < CONTROLS_NUM; st++){ + for (byte te = 0; te < PARAMS_NUM_PER_CTRL; te++) { + preset[st][te] = eeprom.readByte( address + counter ); + counter++; + } + } +} + +void eep_write_preset_params( byte preset_id ){ + int single_param_space_size = CONTROLS_NUM * PARAMS_NUM_PER_CTRL; + int address = EEP_PRSTS_START_ADDR + (preset_id * single_param_space_size); + int counter = 0; + + for (byte st = 0; st < CONTROLS_NUM; st++){ + for (byte te = 0; te < PARAMS_NUM_PER_CTRL; te++) { + eeprom.writeByte(address + counter, preset[st][te]); + counter++; + } + } } diff --git a/schematic/schematic-cache.lib b/schematic/schematic-cache.lib index 0ab8de7..00d7003 100644 --- a/schematic/schematic-cache.lib +++ b/schematic/schematic-cache.lib @@ -486,6 +486,33 @@ X VCC 8 300 200 100 L 50 50 1 1 P ENDDRAW ENDDEF # +# Memory_EEPROM_24LC64 +# +DEF Memory_EEPROM_24LC64 U 0 20 Y Y 1 F N +F0 "U" -250 250 50 H V C CNN +F1 "Memory_EEPROM_24LC64" 50 250 50 H V L CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +ALIAS 24LC02 24LC00 24LC04 24LC08 24LC01 24LC512 24LC64 24LC1025 24LC32 24LC256 24LC128 CAT24C256 CAT24C128 +$FPLIST + DIP*W7.62mm* + SOIC*3.9x4.9mm* + TSSOP*4.4x3mm*P0.65mm* + DFN*3x2mm*P0.5mm* +$ENDFPLIST +DRAW +S -300 200 300 -200 1 1 10 f +X A0 1 -400 100 100 R 50 50 1 1 I +X A1 2 -400 0 100 R 50 50 1 1 I +X A2 3 -400 -100 100 R 50 50 1 1 I +X GND 4 0 -300 100 U 50 50 1 1 W +X SDA 5 400 100 100 L 50 50 1 1 B +X SCL 6 400 0 100 L 50 50 1 1 I +X WP 7 400 -100 100 L 50 50 1 1 I +X VCC 8 0 300 100 D 50 50 1 1 W +ENDDRAW +ENDDEF +# # Switch_SW_Push # DEF Switch_SW_Push SW 0 40 N N 1 F N diff --git a/schematic/schematic.pdf b/schematic/schematic.pdf index a32bcb2..2703aee 100644 Binary files a/schematic/schematic.pdf and b/schematic/schematic.pdf differ diff --git a/schematic/schematic.sch b/schematic/schematic.sch index b2d70fb..d020a13 100644 --- a/schematic/schematic.sch +++ b/schematic/schematic.sch @@ -6,11 +6,11 @@ $Descr A4 11693 8268 encoding utf-8 Sheet 1 1 Title "MIDI Drawbar Commandar" -Date "2019-04-02" -Rev "ver. 3.0" +Date "2020-02-15" +Rev "ver. 4.0" Comp "UBI Stage" Comment1 "sgaruti@gmail.com" -Comment2 "" +Comment2 "this version adds eeprom memory" Comment3 "" Comment4 "" $EndDescr @@ -1299,9 +1299,6 @@ F 3 "~" H 3200 6150 50 0001 C CNN $EndComp Wire Wire Line 2050 5350 2050 5550 -Wire Wire Line - 950 3950 1050 3950 -Connection ~ 950 3950 NoConn ~ 3400 6250 NoConn ~ 3400 6150 NoConn ~ 3400 6050 @@ -1316,24 +1313,8 @@ F 3 "" H 3400 5950 50 0001 C CNN 1 3400 5950 -1 0 0 1 $EndComp -Connection ~ 850 3950 -Wire Wire Line - 550 3950 850 3950 -Wire Wire Line - 850 3950 950 3950 Wire Wire Line 950 5850 950 5350 -$Comp -L Interface_Expansion:MCP23017_SP U1 -U 1 1 5C8F91DE -P 1650 4650 -F 0 "U1" V 1650 5931 50 0000 C CNN -F 1 "MCP23017_SP" V 1800 5850 50 0000 C CNN -F 2 "Package_DIP:DIP-28_W7.62mm" H 1850 3650 50 0001 L CNN -F 3 "http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf" H 1850 3550 50 0001 L CNN - 1 1650 4650 - 0 1 1 0 -$EndComp NoConn ~ 1750 3950 NoConn ~ 1850 3950 NoConn ~ 7150 3650 @@ -1587,7 +1568,7 @@ L Connector_Generic:Conn_02x13_Counter_Clockwise J8 U 1 1 5CA980CA P 1950 2950 F 0 "J8" V 2000 2200 50 0000 C CNN -F 1 "Teensy Digital Connector" V 1650 2300 50 0000 C CNN +F 1 "Teensy Digital Connector" V 1900 1750 50 0000 C CNN F 2 "" H 1950 2950 50 0001 C CNN F 3 "~" H 1950 2950 50 0001 C CNN 1 1950 2950 @@ -1873,14 +1854,11 @@ Wire Wire Line Connection ~ 2450 850 Wire Wire Line 2450 850 2100 850 -Connection ~ 1050 3950 Wire Wire Line 1550 3950 1550 3850 Connection ~ 1550 3850 Wire Wire Line - 2350 3950 2350 3450 -Wire Wire Line - 2450 3350 2450 3950 + 2450 3350 2450 3850 Wire Wire Line 3400 6350 3500 6350 Wire Wire Line @@ -1917,7 +1895,7 @@ Text Notes 8700 5700 0 50 ~ 0 Drawbars Board Text Notes 2800 1500 0 50 ~ 0 Jack pedals assembly -Text Notes 2950 4250 0 50 ~ 0 +Text Notes 3000 5200 0 50 ~ 0 Control Board\nButtons/Led $Comp L power:+3V3 #PWR? @@ -1930,14 +1908,6 @@ F 3 "" H 2750 4650 50 0001 C CNN 1 2750 4650 1 0 0 -1 $EndComp -Wire Bus Line - 750 5950 1450 5950 -Wire Bus Line - 750 6650 3500 6650 -Wire Bus Line - 7550 3250 7550 4900 -Wire Bus Line - 6100 4900 7550 4900 $Comp L power:GND #PWR? U 1 1 5CACBC14 @@ -1960,4 +1930,95 @@ F 3 "" H 4750 3050 50 0001 C CNN 1 4750 3050 -1 0 0 1 $EndComp +$Comp +L Memory_EEPROM:24LC64 U4 +U 1 1 5E48F1C2 +P 3150 3750 +F 0 "U4" H 3150 3269 50 0000 C CNN +F 1 "24LC64" H 3150 3360 50 0000 C CNN +F 2 "" H 3150 3750 50 0001 C CNN +F 3 "http://ww1.microchip.com/downloads/en/DeviceDoc/21189f.pdf" H 3150 3750 50 0001 C CNN + 1 3150 3750 + -1 0 0 1 +$EndComp +Wire Wire Line + 2350 3950 2350 3750 +Connection ~ 1050 3950 +Wire Wire Line + 950 3950 1050 3950 +Connection ~ 950 3950 +Wire Wire Line + 850 3950 950 3950 +Wire Wire Line + 550 3950 850 3950 +Connection ~ 850 3950 +$Comp +L Interface_Expansion:MCP23017_SP U1 +U 1 1 5C8F91DE +P 1650 4650 +F 0 "U1" V 1650 5931 50 0000 C CNN +F 1 "MCP23017_SP" V 1800 5850 50 0000 C CNN +F 2 "Package_DIP:DIP-28_W7.62mm" H 1850 3650 50 0001 L CNN +F 3 "http://ww1.microchip.com/downloads/en/DeviceDoc/20001952C.pdf" H 1850 3550 50 0001 L CNN + 1 1650 4650 + 0 1 1 0 +$EndComp +Wire Wire Line + 2750 3850 2450 3850 +Connection ~ 2450 3850 +Wire Wire Line + 2450 3850 2450 3950 +Wire Wire Line + 2750 3750 2350 3750 +Connection ~ 2350 3750 +Wire Wire Line + 2350 3750 2350 3450 +Wire Wire Line + 3550 3850 3550 4050 +Wire Wire Line + 3550 4050 3150 4050 +$Comp +L power:+3V3 #PWR? +U 1 1 5E674495 +P 3150 4050 +F 0 "#PWR?" H 3150 3900 50 0001 C CNN +F 1 "+3V3" H 3165 4223 50 0000 C CNN +F 2 "" H 3150 4050 50 0001 C CNN +F 3 "" H 3150 4050 50 0001 C CNN + 1 3150 4050 + -1 0 0 1 +$EndComp +Connection ~ 3150 4050 +Wire Wire Line + 3550 3750 3550 3650 +Wire Wire Line + 3550 3450 3150 3450 +Connection ~ 3550 3650 +Wire Wire Line + 3550 3650 3550 3450 +$Comp +L power:GND #PWR? +U 1 1 5E6D20BB +P 3550 3450 +F 0 "#PWR?" H 3550 3200 50 0001 C CNN +F 1 "GND" H 3555 3277 50 0000 C CNN +F 2 "" H 3550 3450 50 0001 C CNN +F 3 "" H 3550 3450 50 0001 C CNN + 1 3550 3450 + -1 0 0 1 +$EndComp +Connection ~ 3550 3450 +Wire Wire Line + 2750 3650 2750 3450 +Wire Wire Line + 2750 3450 3150 3450 +Wire Bus Line + 750 5950 1450 5950 +Wire Bus Line + 750 6650 3500 6650 +Wire Bus Line + 7550 3250 7550 4900 +Wire Bus Line + 6100 4900 7550 4900 +Connection ~ 3150 3450 $EndSCHEMATC