├── images ├── build_1.jpg ├── build_2.jpg ├── hot_snot.jpg ├── wiring_mess.jpg ├── ftdi_adaptor.jpg ├── midi_muppet_hx.jpg ├── state_overview.png └── midi_muppet_schem.png ├── LICENSE.txt ├── README.md └── midi_muppet_hx_2btn.ino /images/build_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/build_1.jpg -------------------------------------------------------------------------------- /images/build_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/build_2.jpg -------------------------------------------------------------------------------- /images/hot_snot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/hot_snot.jpg -------------------------------------------------------------------------------- /images/wiring_mess.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/wiring_mess.jpg -------------------------------------------------------------------------------- /images/ftdi_adaptor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/ftdi_adaptor.jpg -------------------------------------------------------------------------------- /images/midi_muppet_hx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/midi_muppet_hx.jpg -------------------------------------------------------------------------------- /images/state_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/state_overview.png -------------------------------------------------------------------------------- /images/midi_muppet_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattzzw/midi_muppet_hx_2btn/HEAD/images/midi_muppet_schem.png -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Matthias Wientapper 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIDI Muppet HX 2 | 3 | This is a small Arduino based two button MIDI foot switch for the Helix HX Stomp. It is more flexible and more powerful than the "normal" foot switches connected via TRS cable and as a bonus you can still use an expression pedal hooked up to your HX Stomp. 4 | 5 | ![MIDI Muppet HX](images/midi_muppet_hx.jpg) 6 | 7 | The MIDI Muppet HX can 8 | - scroll up/down through presets (scroll mode) 9 | - act as FS4/FS5 (footswitch/fs mode) 10 | - quickly access snapshot mode and scroll up/down through snapshots 11 | - bring up the tuner via long press left (dn) button 12 | - act as a two button LOOPER controller 13 | 14 | ## MIDI Muppet Main Modes 15 | 16 | The unit supports three basic modes of operation. The LED will indicate the current mode: 17 | 18 | | Mode | LED on boot | LED in operation | 19 | |------|-----|-----------------| 20 | | Scroll preset | flash red | scroll preset: red, snapshot: green, tuner: flash green | 21 | | Footswitch FS4/FS5 | flash green | green, tuner: flash green | 22 | | Looper | flash red/green | play: green, record: red, overdub: yellow | 23 | 24 | To select a mode, **press and hold both buttons** until one of the above LED patterns shows up and the mode is selected. 25 | 26 | Next time the unit is powered on the unit will automatically switch to the mode used last. 27 | 28 | ![Overview](images/state_overview.png) 29 | 30 | ### Using the Modes: 31 | 32 | SCROLL Mode: up/dn switches program patches 33 | long press dn: toggle TUNER 34 | long press up: toggle SNAPSHOT mode 35 | 36 | Footswitch Mode: up/dn emulate footswitch FS4/FS5 37 | long press dn: toggle TUNER 38 | long press up: toggle SNAPSHOT mode 39 | 40 | SNAPSHOT Mode: up/dn switches snapshot 41 | long press dn: toggle TUNER 42 | long press up: back to last mode (FS or SCROLL) 43 | TUNER Mode: up or dn back to prev Mode 44 | 45 | LOOPER Mode (if enabled): 46 | 47 | LOOPER Mode: dn toggles record/overdub 48 | up toggles play/stop 49 | long press up toggles undo/redo 50 | 51 | ### Disabling LOOPER Control 52 | 53 | The LOOPER mode can be disabled. This can be handy if you want to cycle between SCROLL and FS modes more quickly or you simply don't need the LOOPER mode: 54 | 55 | - Press **up** while powering up the MIDI Muppet to toggle LOOPER control. The device will rapidly flash **red** 20 times. After a second the device will slowly flash the **red** LED to indicate that LOOPER mode has been **disabled** or green that the LOOPER mode has been **enabled**. 56 | - Press **up** to **enable** LOOPER control. (**green** LED will flash.) 57 | - Press **dn** to **disable** LOOPER control. (**red** LED will flash.) 58 | - Press and hold **up** and **dn** to exit LOOPER control configuration. 59 | 60 | LOOPER control configuration will be stored in EEPROM and will be loaded on restart. 61 | 62 | ### Setting the MIDI Channel 63 | MIDI channel can be set to any value between 1 and 16. HX Stomp listens on channel 1 per default. 64 | 65 | To change the MIDI Channel: 66 | - Press and hold **dn** while powering up the MIDI Muppet until the device flashes rapidly 20 times **green**. After a second the device will indicate the currently set MIDI channel by slowly flashing the green LED (1 flash = channel 1, ..., 16 flashes = channel 16). 67 | - Press **up** to increase the MIDI channel or press **dn** to decrease the channel. 68 | - Press and hold **up** and **dn** to exit MIDI channel configuration. 69 | 70 | MIDI Channel configuration will be stored in EEPROM and will be loaded on restart. 71 | 72 | 73 | ## Building MIDI Muppet HX 74 | Parts are around 20€: 75 | - Stomp case: e.g. Hammond 1590A 76 | - 2 momentary foot switches 77 | - Arduino Pro Mini with programming headers populated 78 | - MIDI/DIN Socket 79 | - 2,1 mm power Socket 80 | - bicolor LED (red/green, common cathode) 81 | - 4 x 220R resistors (5V version of Arduino) 82 | - Or 2 x 220R, 1 x 10R, 1 x 33R (3.3V version of Arduino) 83 | - FTDI serial adaptor (for programming) 84 | 85 | Make sure you know whether you have the 3.3V or the 5V version of the Arduino Pro Mini. How to find out? Apply 9V to the RAW pin and measure the VCC pin. 86 | 87 | Luckily MIDI works with 3.3V, so if you are using the 3.3V version you have to change the resistors for the MIDI TX line (pin 5 of MIDI plug) to 10 ohms and for the MIDI voltage reference line (pin 4 of MIDI plug) to 33 ohms. 88 | 89 | A little bit of drilling, soldering and hot snot will be required. 90 | 91 | ![building MIDI Muppet](images/build_1.jpg) 92 | 93 | ![drilled](images/build_2.jpg) 94 | 95 | ### Wiring 96 | - Arduino D2, D3: Button Up/Down to ground 97 | - Arduino D4, D5: via 220R resistor to LED green/red anode, cathode to ground 98 | - Arduino TX pin: via 220R resistor to MIDI pin 5 (data line) 99 | - Arduino 5V/VCC pin: via 220R resistor to MIDI pin 4 (voltage reference line) 100 | - Arduino RAW pin: 9V from power socket 101 | - Arduino GNC pin: GND from power socket 102 | 103 | ![schematic](images/midi_muppet_schem.png) 104 | 105 | ![Wiring](images/wiring_mess.jpg) 106 | 107 | I put a little bit of capton tape on backside of a foot switch and on the the inside of the case for isolation and fixated the Arduino PCB with a little bit of hot snot. 108 | 109 | ![Hot Snot](images/hot_snot.jpg) 110 | 111 | ### The Code 112 | The code requires the OneButton and the JC_Button library to be installed. The Arduino library manager will be your friend. 113 | 114 | ### Programming 115 | Disconnect external power supply first! The FTDI adaptor will provide power. 116 | 117 | Hook up the FTDI adaptor to the Arduino board, select "Arduino Pro or Pro Mini" in your Arduino IDE, load the code, compile and upload. 118 | 119 | The LED will flash rapidly on boot. Congratulations, you have just created a powerful controller for your HX Stomp. Have fun. 120 | 121 | ![](images/ftdi_adaptor.jpg) 122 | -------------------------------------------------------------------------------- /midi_muppet_hx_2btn.ino: -------------------------------------------------------------------------------- 1 | 2 | /************************************************************************** 3 | 4 | BSD 3-Clause License 5 | 6 | Copyright (c) 2020, Matthias Wientapper 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, this 13 | list of conditions and the following disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above copyright notice, 16 | this list of conditions and the following disclaimer in the documentation 17 | and/or other materials provided with the distribution. 18 | 19 | 3. Neither the name of the copyright holder nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | 35 | Midi Foot Switch for HX Stomp 36 | ============================= 37 | - Button Up/Down on pins D2, D3 38 | - LED green/red D4, D5 39 | - requires OneButton lib https://github.com/mathertel/OneButton 40 | - requires JC_Button lib https://github.com/JChristensen/JC_Button 41 | 42 | We are using two different button libraries for different purposes: 43 | - OneButton to detect a long press without detecting a short press first. 44 | This means the action will be evaluated on releasing the button, 45 | which is ok for most cases but bad for timing critical actions 46 | like when we are in looper mode. 47 | - JC_Button to detect a short press as soon as the button is pressed down. 48 | This button library is used in looper mode only. 49 | 50 | SCROLL Mode: up/dn switches prog patches 51 | long press dn: TUNER 52 | long press up: SNAPSHOT mode 53 | up + dn: FS mode 54 | FS Mode: up/dn emulate FS4/FS5 55 | long press dn: TUNER 56 | long press up: SNAPSHOT mode 57 | up + dn: SCROLL mode 58 | SNAPSHOT Mode: up/dn switches snapshot 59 | long press dn: TUNER 60 | long press up: FS mode 61 | TUNER Mode: up or dn back to prev mode 62 | LOOPER Mode: dn toggles record/overdub 63 | up toggles play/stop 64 | long press up toggles undo/redo 65 | 66 | **************************************************************************/ 67 | 68 | #include 69 | #include 70 | #include 71 | 72 | #include 73 | 74 | // GPIO pins used 75 | #define BTN_UP 2 76 | #define BTN_DN 3 77 | #define LED_GRN 4 78 | #define LED_RED 5 79 | 80 | // EEPROM addresses 81 | #define OP_MODE_ADDR 0 // stores looper mode of operation 82 | #define LOOPER_MODE_ADDR 1 // stores if looper control is enabled 83 | #define MIDI_CHANNEL_ADDR 2 // stores the midi channel 84 | 85 | // Adjust red LED brightness 0-255 (full on was way too bright for me) 86 | #define LED_RED_BRIGHTNESS 25 87 | // on/off delay when we flash a LED 88 | #define LED_FLASH_DELAY 30 89 | 90 | OneButton btnUp(BTN_UP, true); 91 | OneButton btnDn(BTN_DN, true); 92 | 93 | Button jc_btnUp(BTN_UP); 94 | Button jc_btnDn(BTN_DN); 95 | 96 | enum modes_t {SCROLL, SNAPSHOT, FS, LOOPER, TUNER, CHANNEL_CFG, LOOPER_CFG}; // modes of operation 97 | static modes_t MODE; // current mode 98 | static modes_t LAST_MODE; // last mode 99 | static modes_t MODE_BEFORE_SNAPSHOT; // last mode before snap shot mode 100 | 101 | enum lmodes_t {PLAY, RECORD, OVERDUB, STOP}; // Looper modes 102 | static lmodes_t LPR_MODE; 103 | 104 | bool with_looper = true; 105 | uint8_t midi_channel = 0; 106 | 107 | void (*Reset)(void) = 0; 108 | 109 | void setup() { 110 | 111 | // LEDs 112 | pinMode(LED_RED, OUTPUT); 113 | pinMode(LED_GRN, OUTPUT); 114 | 115 | // Buttons: 116 | btnUp.setClickTicks(50); 117 | btnUp.attachClick(upClick); 118 | btnUp.attachLongPressStart(upLongPressStart); 119 | 120 | btnDn.setClickTicks(50); 121 | btnDn.attachClick(dnClick); 122 | btnDn.attachLongPressStart(dnLongPressStart); 123 | 124 | // Set MIDI baud rate: 125 | Serial.begin(31250); 126 | 127 | 128 | // restore MODE from EEPROM 129 | MODE = (modes_t) EEPROM.read(OP_MODE_ADDR); 130 | if (MODE > 4){ 131 | // no valid value in eeprom found. (Maybe this is the first power up ever?) 132 | MODE = SCROLL; 133 | } 134 | 135 | // restore looper config from adr. 1 136 | with_looper = EEPROM.read(LOOPER_MODE_ADDR); 137 | if (with_looper > 1) 138 | with_looper = false; 139 | 140 | // restore MIDI channel 141 | midi_channel = EEPROM.read(MIDI_CHANNEL_ADDR); 142 | if (midi_channel > 15){ 143 | // set channel to 0 if data not valid 144 | EEPROM.update(MIDI_CHANNEL_ADDR, 0); 145 | midi_channel = 0; 146 | } 147 | 148 | if (digitalRead(BTN_DN) == 0 && digitalRead(BTN_UP) == 1) { 149 | // btn dn pressed: configure MIDI channel 150 | MODE = CHANNEL_CFG; 151 | flashLED(20, LED_GRN, LED_FLASH_DELAY); 152 | // 'display' configure MIDI channel 153 | delay(1000); 154 | flashLED(midi_channel + 1, LED_GRN, 500); 155 | } 156 | 157 | if (digitalRead(BTN_DN) == 1 && digitalRead(BTN_UP) == 0) { 158 | // btn up pressed: toggle looper ctrl enabled/disabled 159 | MODE = LOOPER_CFG; 160 | flashLED(20, LED_RED, LED_FLASH_DELAY); 161 | delay(1000); 162 | if (with_looper) 163 | flashLED(1, LED_GRN, 500); 164 | else 165 | flashLED(1, LED_RED, 500); 166 | } 167 | 168 | 169 | // restore mode on HX Stomp as well 170 | if (MODE == SNAPSHOT) 171 | midiCtrlChange(71, 3); // set snapshot mode 172 | else if (MODE == FS) 173 | midiCtrlChange(71, 0); // set stomp mode 174 | else if (MODE == SCROLL) 175 | midiCtrlChange(71, 0); // set stomp mode 176 | 177 | MODE_BEFORE_SNAPSHOT = MODE; 178 | 179 | // indicate mode via LEDs 180 | if (MODE == LOOPER) { 181 | flashRedGreen(10); 182 | // we are in looper mode, so we are using the jc_button class for action on button press 183 | // (OneButton acts on button release) 184 | jc_btnUp.begin(); 185 | jc_btnDn.begin(); 186 | } 187 | else if (MODE == SCROLL) 188 | flashLED(10, LED_RED, LED_FLASH_DELAY); 189 | else if (MODE == FS) 190 | flashLED(10, LED_GRN, LED_FLASH_DELAY); 191 | 192 | // Looper default state 193 | LPR_MODE = STOP; 194 | 195 | } 196 | 197 | 198 | void loop() { 199 | 200 | if (MODE == LOOPER) { 201 | jc_btnDn.read(); // DN Button handled by JC_Button 202 | btnUp.tick(); // Up Button handled by OneButton 203 | 204 | if (jc_btnDn.wasPressed() && digitalRead(BTN_UP) == 1) // attach handler 205 | jc_dnClick(); 206 | 207 | } else { 208 | btnUp.tick(); // both buttons handled by OneButton 209 | btnDn.tick(); 210 | } 211 | 212 | handle_leds(); 213 | } 214 | 215 | /* ------------------------------------------------- */ 216 | /* --- OneButton Callback Routines ---*/ 217 | /* ------------------------------------------------- */ 218 | 219 | void dnClick() { 220 | switch (MODE) 221 | { 222 | case SCROLL: 223 | patchDown(); 224 | flashLED(2, LED_RED, LED_FLASH_DELAY); 225 | break; 226 | case TUNER: 227 | midiCtrlChange(68, 0); // toggle tuner 228 | flashLED(2, LED_RED, LED_FLASH_DELAY); 229 | MODE = LAST_MODE; 230 | break; 231 | case SNAPSHOT: 232 | midiCtrlChange(69, 9); // prev snapshot 233 | flashLED(2, LED_RED, LED_FLASH_DELAY); 234 | break; 235 | case FS: 236 | midiCtrlChange(52, 0); // emulate FS 4 237 | flashLED(2, LED_RED, LED_FLASH_DELAY); 238 | break; 239 | case LOOPER: 240 | switch (LPR_MODE) { 241 | case STOP: 242 | LPR_MODE = RECORD; 243 | midiCtrlChange(60, 127); // Looper record 244 | break; 245 | case RECORD: 246 | LPR_MODE = PLAY; 247 | midiCtrlChange(61, 127); // Looper play 248 | break; 249 | case PLAY: 250 | LPR_MODE = OVERDUB; 251 | midiCtrlChange(60, 0); // Looper overdub 252 | break; 253 | case OVERDUB: 254 | LPR_MODE = PLAY; 255 | midiCtrlChange(61, 127); // Looper play 256 | break; 257 | } 258 | break; 259 | case CHANNEL_CFG: 260 | if(midi_channel > 0) 261 | midi_channel--; 262 | flashLED(midi_channel + 1, LED_GRN, 500); 263 | EEPROM.update(MIDI_CHANNEL_ADDR, midi_channel); 264 | break; 265 | case LOOPER_CFG: 266 | with_looper = false; 267 | flashLED(1, LED_RED, 500); 268 | EEPROM.update(LOOPER_MODE_ADDR, with_looper); 269 | break; 270 | } 271 | } 272 | void upClick() { 273 | switch (MODE) 274 | { 275 | case SCROLL: 276 | patchUp(); 277 | flashLED(2, LED_RED, LED_FLASH_DELAY); 278 | break; 279 | case TUNER: 280 | midiCtrlChange(68, 0); // toggle tuner 281 | flashLED(2, LED_RED, LED_FLASH_DELAY); 282 | MODE = LAST_MODE; 283 | break; 284 | case SNAPSHOT: 285 | flashLED(2, LED_RED, LED_FLASH_DELAY); 286 | midiCtrlChange(69, 8); // next snapshot 287 | break; 288 | case FS: 289 | flashLED(2, LED_RED, LED_FLASH_DELAY); 290 | midiCtrlChange(53, 0); // emulate FS 5 291 | break; 292 | case LOOPER: 293 | switch (LPR_MODE) { 294 | case STOP: 295 | LPR_MODE = PLAY; 296 | midiCtrlChange(61, 127); // Looper play 297 | break; 298 | case PLAY: 299 | case RECORD: 300 | case OVERDUB: 301 | LPR_MODE = STOP; 302 | midiCtrlChange(61, 0); // Looper stop 303 | break; 304 | } 305 | break; 306 | case CHANNEL_CFG: 307 | if(midi_channel < 15) 308 | midi_channel++; 309 | flashLED(midi_channel + 1, LED_GRN, 500); 310 | EEPROM.update(MIDI_CHANNEL_ADDR, midi_channel); 311 | break; 312 | case LOOPER_CFG: 313 | with_looper = true; 314 | flashLED(1, LED_GRN, 500); 315 | EEPROM.update(LOOPER_MODE_ADDR, with_looper); 316 | break; 317 | 318 | } 319 | } 320 | 321 | void dnLongPressStart() { 322 | if (digitalRead(BTN_UP) == 1) { 323 | switch (MODE) 324 | { 325 | case TUNER: 326 | break; 327 | case SCROLL: 328 | case SNAPSHOT: 329 | case FS: 330 | midiCtrlChange(68, 0); // toggle tuner 331 | flashLED(2, LED_RED, LED_FLASH_DELAY); 332 | LAST_MODE = MODE; 333 | MODE = TUNER; 334 | break; 335 | case LOOPER: 336 | break; 337 | } 338 | } 339 | } 340 | 341 | void upLongPressStart() { 342 | 343 | if (digitalRead(BTN_DN) == 0) { 344 | // yay, both buttons pressed! 345 | // Toggle through modes 346 | switch (MODE) { 347 | case SCROLL: 348 | MODE = FS; 349 | break; 350 | case FS: 351 | if (with_looper) 352 | MODE = LOOPER; 353 | else 354 | MODE = SCROLL; 355 | break; 356 | case LOOPER: 357 | // make sure to switch off looper 358 | midiCtrlChange(61, 0); // Looper stop 359 | MODE = SCROLL; 360 | break; 361 | case SNAPSHOT: 362 | if (with_looper) 363 | MODE = LOOPER; 364 | else 365 | MODE = SCROLL; 366 | break; 367 | case TUNER: 368 | break; 369 | case CHANNEL_CFG: 370 | MODE = LAST_MODE; 371 | break; 372 | } 373 | EEPROM.update(OP_MODE_ADDR, MODE); 374 | // reset the device to reboot in new mode 375 | Reset(); 376 | } else { 377 | // regular long press event: 378 | switch (MODE) 379 | { 380 | case TUNER: 381 | break; 382 | case SCROLL: 383 | // save mode where we entered snapshot mode from 384 | MODE_BEFORE_SNAPSHOT = MODE; 385 | midiCtrlChange(71, 3); // set snapshot mode 386 | flashLED(5, LED_RED, LED_FLASH_DELAY); 387 | MODE = SNAPSHOT; 388 | EEPROM.update(0, MODE); 389 | break; 390 | case SNAPSHOT: 391 | if (MODE_BEFORE_SNAPSHOT == FS) { 392 | midiCtrlChange(71, 0); // set stomp mode 393 | flashLED(5, LED_RED, LED_FLASH_DELAY); 394 | MODE = FS; 395 | } else { 396 | if (MODE_BEFORE_SNAPSHOT == SCROLL) { 397 | midiCtrlChange(71, 0); // set stomp mode 398 | flashLED(5, LED_RED, LED_FLASH_DELAY); 399 | MODE = SCROLL; 400 | } 401 | } 402 | EEPROM.update(0, MODE); 403 | break; 404 | case FS: 405 | // save mode where we entered snapshot mode from 406 | MODE_BEFORE_SNAPSHOT = MODE; 407 | midiCtrlChange(71, 3); // set snapshot mode 408 | flashLED(5, LED_RED, LED_FLASH_DELAY); 409 | MODE = SNAPSHOT; 410 | EEPROM.update(0, MODE); 411 | break; 412 | case LOOPER: 413 | switch (LPR_MODE) { 414 | case PLAY: 415 | case STOP: 416 | midiCtrlChange(63, 127); // looper undo/redo 417 | flashLED(3, LED_RED, LED_FLASH_DELAY); 418 | break; 419 | case RECORD: 420 | case OVERDUB: 421 | break; 422 | } 423 | 424 | break; 425 | } 426 | } 427 | } 428 | 429 | /* ------------------------------------------------- */ 430 | /* --- JC_Button Callback Routines ---*/ 431 | /* ------------------------------------------------- */ 432 | 433 | void jc_dnClick() { 434 | switch (LPR_MODE) { 435 | case STOP: 436 | LPR_MODE = RECORD; 437 | midiCtrlChange(60, 127); // Looper record 438 | break; 439 | case RECORD: 440 | LPR_MODE = PLAY; 441 | midiCtrlChange(61, 127); // Looper play 442 | break; 443 | case PLAY: 444 | LPR_MODE = OVERDUB; 445 | midiCtrlChange(60, 0); // Looper overdub 446 | break; 447 | case OVERDUB: 448 | LPR_MODE = PLAY; 449 | midiCtrlChange(61, 127); // Looper play 450 | break; 451 | } 452 | } 453 | 454 | 455 | 456 | /* ------------------------------------------------- */ 457 | /* --- Midi Routines ---*/ 458 | /* ------------------------------------------------- */ 459 | 460 | // Use these routines if you are using firmware 3.01 or older: 461 | 462 | // HX stomp does not have a native patch up/dn midi command 463 | // so we are switching to scroll mode and emulating a FS1/2 464 | // button press. 465 | /* 466 | void patchUp() { 467 | midiCtrlChange(71, 1); // HX scroll mode 468 | delay(30); 469 | midiCtrlChange(50, 127); // FS 2 (up) 470 | midiCtrlChange(71, 0); // HX stomp mode 471 | } 472 | 473 | void patchDown() { 474 | midiCtrlChange(71, 1); // HX scroll mode 475 | delay(30); 476 | midiCtrlChange(49, 127); // FS 1 (down) 477 | midiCtrlChange(71, 0); // HX stomp mode 478 | } 479 | */ 480 | 481 | // Added in Firmware 3.10: 482 | //New MIDI message: CC 72 value 64-127 = next preset, value 0-63 = previous preset 483 | void patchUp() { 484 | midiCtrlChange(72, 127); // next preset 485 | } 486 | 487 | void patchDown() { 488 | midiCtrlChange(72, 0); // prev preset 489 | } 490 | 491 | 492 | void midiProgChange(uint8_t p) { 493 | Serial.write(0xc0 | midi_channel); // PC message 494 | Serial.write(p); // prog 495 | } 496 | void midiCtrlChange(uint8_t c, uint8_t v) { 497 | Serial.write(0xb0 | midi_channel); // CC message 498 | Serial.write(c); // controller 499 | Serial.write(v); // value 500 | } 501 | 502 | /* ------------------------------------------------- */ 503 | /* --- Misc Stuff ---*/ 504 | /* ------------------------------------------------- */ 505 | void flashLED(uint8_t i, uint8_t led, uint8_t del) 506 | { 507 | uint8_t last_state; 508 | last_state = digitalRead(led); 509 | 510 | for (uint8_t j = 0; j < i; j++) { 511 | digitalWrite(led, HIGH); 512 | delay(del); 513 | digitalWrite(led, LOW); 514 | delay(del); 515 | } 516 | digitalWrite(led, last_state); 517 | } 518 | 519 | void flashRedGreen(uint8_t i) { 520 | uint8_t last_state_r; 521 | uint8_t last_state_g; 522 | last_state_r = digitalRead(LED_RED); 523 | last_state_g = digitalRead(LED_GRN); 524 | 525 | 526 | for (uint8_t j = 0; j < i; j++) { 527 | digitalWrite(LED_RED, LOW); 528 | digitalWrite(LED_GRN, HIGH); 529 | delay(75); 530 | analogWrite(LED_RED, LED_RED_BRIGHTNESS); 531 | digitalWrite(LED_GRN, LOW); 532 | delay(75); 533 | } 534 | digitalWrite(LED_RED, last_state_r); 535 | digitalWrite(LED_GRN, last_state_g); 536 | } 537 | 538 | void handle_leds() { 539 | static unsigned long next = millis(); 540 | 541 | switch (MODE) { 542 | case SCROLL: 543 | // solid red 544 | digitalWrite(LED_GRN, LOW); 545 | analogWrite(LED_RED, LED_RED_BRIGHTNESS); 546 | //digitalWrite(LED_RED, HIGH); 547 | break; 548 | case SNAPSHOT: 549 | // solid green 550 | digitalWrite(LED_GRN, HIGH); 551 | digitalWrite(LED_RED, LOW); 552 | break; 553 | case FS: 554 | // solid green 555 | digitalWrite(LED_RED, LOW); 556 | digitalWrite(LED_GRN, HIGH); 557 | break; 558 | case TUNER: 559 | // blink green 560 | if (millis() - next > 500) { 561 | next += 500; 562 | digitalWrite(LED_GRN, !digitalRead(LED_GRN)); 563 | } 564 | break; 565 | case LOOPER: 566 | switch (LPR_MODE) { 567 | case STOP: 568 | digitalWrite(LED_GRN, LOW); 569 | digitalWrite(LED_RED, LOW); 570 | break; 571 | case PLAY: 572 | digitalWrite(LED_GRN, HIGH); 573 | digitalWrite(LED_RED, LOW); 574 | break; 575 | case RECORD: 576 | digitalWrite(LED_GRN, LOW); 577 | analogWrite(LED_RED, LED_RED_BRIGHTNESS); 578 | break; 579 | case OVERDUB: 580 | // yellow 581 | digitalWrite(LED_GRN, HIGH); 582 | analogWrite(LED_RED, LED_RED_BRIGHTNESS); 583 | break; 584 | } 585 | break; 586 | } 587 | } 588 | --------------------------------------------------------------------------------