Please ensure Javascript is enabled for purposes of website accessibility Jump to content

Titus115

Members
  • Posts

    1
  • Joined

  • Last visited

Everything posted by Titus115

  1. did this and combined it with another project that counts the clock sync. In addition to the midi input and output I added a small relay board. Also an additional function to receive midi control change messages. So I have your functionality and the ability to send tap to my analog delay pedal and change the channel on my amp from dirty to clean. /************************************************************************** BSD 3-Clause License Copyright (c) 2020, Matthias Wientapper All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Midi Foot Switch for HX Stomp ============================= - Button Up/Down on pins D2, D3 - LED green/red D4, D5 - requires OneButton lib https://github.com/mathertel/OneButton - requires JC_Button lib https://github.com/JChristensen/JC_Button We are using two different button libraries for different purposes: - OneButton to detect a long press without detecting a short press first. This means the action will be evaluated on releasing the button, which is ok for most cases but bad for timing critical actions like when we are in looper mode. - JC_Button to detect a short press as soon as the button is pressed down. This button library is used in looper mode only. SCROLL Mode: up/dn switches prog patches long press dn: TUNER long press up: SNAPSHOT mode up + dn: FS mode FS Mode: up/dn emulate FS4/FS5 long press dn: TUNER long press up: SNAPSHOT mode up + dn: SCROLL mode SNAPSHOT Mode: up/dn switches snapshot long press dn: TUNER long press up: FS mode TUNER Mode: up or dn back to prev mode LOOPER Mode: dn toggles record/overdub up toggles play/stop long press up toggles undo/redo **************************************************************************/ #include <Wire.h> #include <OneButton.h> #include <JC_Button.h> #include <MIDI.h> // Add Midi Library #include <EEPROM.h> #define BTN_UP 2 #define BTN_DN 3 #define LED_GRN 4 #define LED_RED 5 #define AMP_RELAY 6 #define TAP_RELAY 7 #define LED 13 // Adjust red LED brightness 0-255 (full on was way too bright for me) #define LED_RED_BRIGHTNESS 25 MIDI_CREATE_DEFAULT_INSTANCE(); OneButton btnUp(BTN_UP, true); OneButton btnDn(BTN_DN, true); Button jc_btnUp(BTN_UP); Button jc_btnDn(BTN_DN); enum modes_t {SCROLL, SNAPSHOT, FS, LOOPER, TUNER}; // modes of operation static modes_t MODE; // current mode static modes_t LAST_MODE; // last mode static modes_t MODE_BEFORE_SNAPSHOT; // last mode before snap shot mode enum lmodes_t {PLAY, RECORD, OVERDUB, STOP}; // Looper modes static lmodes_t LPR_MODE; bool with_looper = true; bool led = true; void (*Reset)(void) = 0; //MERGE SETUP START #include <elapsedMillis.h> elapsedMillis timeElapsed2; elapsedMillis timeElapsed; unsigned long prevInterval ; unsigned long interval ; int tapCount = 0; byte midi_start = 0xfa; byte midi_stop = 0xfc; byte midi_clock = 0xf8; byte midi_continue = 0xfb; int play_flag = 0; byte data; byte counter; byte clickCounter; //int tapPin = 13; //MERGE SETUP END void setup() { uint8_t eeprom_val; uint8_t looper_val; // LEDs pinMode(LED_RED, OUTPUT); pinMode(LED_GRN, OUTPUT); // Buttons: btnUp.setClickTicks(50); btnUp.attachClick(upClick); btnUp.attachLongPressStart(upLongPressStart); btnDn.setClickTicks(50); btnDn.attachClick(dnClick); btnDn.attachLongPressStart(dnLongPressStart); // Set MIDI baud rate: Serial.begin(31250); // get last used mode from eeprom adr. 0 eeprom_val = EEPROM.read(0); // restore last mode, if possible (= valid value) if (eeprom_val < 4) MODE = (modes_t)eeprom_val; else // no valid value in eeprom found. (Maybe this is the first power up ever?) MODE = SCROLL; // restore mode on HX Stomp as well if (MODE == SNAPSHOT) midiCtrlChange(71, 3); // set snapshot mode else if (MODE == FS) midiCtrlChange(71, 0); // set stomp mode else if (MODE == SCROLL) midiCtrlChange(71, 0); // set stomp mode MODE_BEFORE_SNAPSHOT = MODE; // indicate mode via LEDs if (MODE == LOOPER) { flashRedGreen(10); // we are in looper mode, so we are using the jc_button class for action on button press // (OneButton acts on button release) jc_btnUp.begin(); jc_btnDn.begin(); } else if (MODE == SCROLL) flashLED(10, LED_RED); else if (MODE == FS) flashLED(10, LED_GRN); // Looper default state LPR_MODE = STOP; // check if btd_dn or btn_up is still pressed on power on // and enable disable looper mode availability // (buttons are low active) if (digitalRead(BTN_DN) == 0 && digitalRead(BTN_UP) == 1) { // btn dn pressed with_looper = false; EEPROM.update(1, with_looper); delay(500); flashLED(5, LED_RED); } if (digitalRead(BTN_DN) == 1 && digitalRead(BTN_UP) == 0) { // btn up pressed with_looper = true; EEPROM.update(1, with_looper); delay(500); flashLED(5, LED_GRN); } // restore looper config from adr. 1 looper_val = EEPROM.read(1); if (looper_val < 2) with_looper = looper_val; else with_looper = true; pinMode (AMP_RELAY, OUTPUT); // Set Arduino board pin 13 to output //pinMode (13, OUTPUT); pinMode (TAP_RELAY,OUTPUT); MIDI.begin(MIDI_CHANNEL_OMNI); // Initialize the Midi Library. MIDI.setHandleControlChange(MyCCFunction); MIDI.setHandleStart(countStart); MIDI.setHandleContinue(countContinue); MIDI.setHandleStop(countStop); MIDI.setHandleClock(clockHandler); } void loop() { if (MODE == LOOPER) { jc_btnDn.read(); // DN Button handled by JC_Button btnUp.tick(); // Up Button handled by OneButton if (jc_btnDn.wasPressed() && digitalRead(BTN_UP) == 1) // attach handler jc_dnClick(); } else { btnUp.tick(); // both buttons handled by OneButton btnDn.tick(); } handle_leds(); MIDI.read(); } /* ------------------------------------------------- */ /* --- OneButton Callback Routines ---*/ /* ------------------------------------------------- */ void dnClick() { switch (MODE) { case SCROLL: patchDown(); flashLED(2, LED_RED); break; case TUNER: midiCtrlChange(68, 0); // toggle tuner flashLED(2, LED_RED); MODE = LAST_MODE; break; case SNAPSHOT: midiCtrlChange(69, 9); // prev snapshot flashLED(2, LED_RED); break; case FS: midiCtrlChange(52, 0); // emulate FS 4 flashLED(2, LED_RED); break; case LOOPER: switch (LPR_MODE) { case STOP: LPR_MODE = RECORD; midiCtrlChange(60, 127); // Looper record break; case RECORD: LPR_MODE = PLAY; midiCtrlChange(61, 127); // Looper play break; case PLAY: LPR_MODE = OVERDUB; midiCtrlChange(60, 0); // Looper overdub break; case OVERDUB: LPR_MODE = PLAY; midiCtrlChange(61, 127); // Looper play break; } break; } } void upClick() { switch (MODE) { case SCROLL: patchUp(); flashLED(2, LED_RED); break; case TUNER: midiCtrlChange(68, 0); // toggle tuner flashLED(2, LED_RED); MODE = LAST_MODE; break; case SNAPSHOT: flashLED(2, LED_RED); midiCtrlChange(69, 8); // next snapshot break; case FS: flashLED(2, LED_RED); midiCtrlChange(53, 0); // emulate FS 5 break; case LOOPER: switch (LPR_MODE) { case STOP: LPR_MODE = PLAY; midiCtrlChange(61, 127); // Looper play break; case PLAY: case RECORD: case OVERDUB: LPR_MODE = STOP; midiCtrlChange(61, 0); // Looper stop break; } break; } } void dnLongPressStart() { if (digitalRead(BTN_UP) == 1) { switch (MODE) { case TUNER: break; case SCROLL: case SNAPSHOT: case FS: midiCtrlChange(68, 0); // toggle tuner flashLED(2, LED_RED); LAST_MODE = MODE; MODE = TUNER; break; case LOOPER: break; } } } void upLongPressStart() { if (digitalRead(BTN_DN) == 0) { // yay, both buttons pressed! // Toggle through modes switch (MODE) { case SCROLL: MODE = FS; break; case FS: if (with_looper) MODE = LOOPER; else MODE = SCROLL; break; case LOOPER: // make sure to switch off looper midiCtrlChange(61, 0); // Looper stop MODE = SCROLL; break; case SNAPSHOT: if (with_looper) MODE = LOOPER; else MODE = SCROLL; break; case TUNER: break; } EEPROM.update(0, MODE); // reset the device to reboot in new mode Reset(); } else { // regular long press event: switch (MODE) { case TUNER: break; case SCROLL: // save mode where we entered snapshot mode from MODE_BEFORE_SNAPSHOT = MODE; midiCtrlChange(71, 3); // set snapshot mode flashLED(5, LED_RED); MODE = SNAPSHOT; EEPROM.update(0, MODE); break; case SNAPSHOT: if (MODE_BEFORE_SNAPSHOT == FS) { midiCtrlChange(71, 0); // set stomp mode flashLED(5, LED_RED); MODE = FS; } else { if (MODE_BEFORE_SNAPSHOT == SCROLL) { midiCtrlChange(71, 0); // set stomp mode flashLED(5, LED_RED); MODE = SCROLL; } } EEPROM.update(0, MODE); break; case FS: // save mode where we entered snapshot mode from MODE_BEFORE_SNAPSHOT = MODE; midiCtrlChange(71, 3); // set snapshot mode flashLED(5, LED_RED); MODE = SNAPSHOT; EEPROM.update(0, MODE); break; case LOOPER: switch (LPR_MODE) { case PLAY: case STOP: midiCtrlChange(63, 127); // looper undo/redo flashLED(3, LED_RED); break; case RECORD: case OVERDUB: break; } break; } } } /* ------------------------------------------------- */ /* --- JC_Button Callback Routines ---*/ /* ------------------------------------------------- */ void jc_dnClick() { switch (LPR_MODE) { case STOP: LPR_MODE = RECORD; midiCtrlChange(60, 127); // Looper record break; case RECORD: LPR_MODE = PLAY; midiCtrlChange(61, 127); // Looper play break; case PLAY: LPR_MODE = OVERDUB; midiCtrlChange(60, 0); // Looper overdub break; case OVERDUB: LPR_MODE = PLAY; midiCtrlChange(61, 127); // Looper play break; } } /* ------------------------------------------------- */ /* --- Midi Routines ---*/ /* ------------------------------------------------- */ // HX stomp does not have a native patch up/dn midi command // so we are switching to scroll mode and emulating a FS1/2 // button press. void patchUp() { midiCtrlChange(71, 1); // HX scroll mode delay(30); midiCtrlChange(50, 127); // FS 2 (up) midiCtrlChange(71, 0); // HX stomp mode } void patchDown() { midiCtrlChange(71, 1); // HX scroll mode delay(30); midiCtrlChange(49, 127); // FS 1 (down) midiCtrlChange(71, 0); // HX stomp mode } void midiProgChange(uint8_t p) { Serial.write(0xc0); // PC message Serial.write(p); // prog } void midiCtrlChange(uint8_t c, uint8_t v) { Serial.write(0xb0); // CC message Serial.write(c); // controller Serial.write(v); // value } /* ------------------------------------------------- */ /* --- Misc Stuff ---*/ /* ------------------------------------------------- */ void flashLED(uint8_t i, uint8_t led) { uint8_t last_state; last_state = digitalRead(led); for (uint8_t j = 0; j < i; j++) { digitalWrite(led, HIGH); delay(30); digitalWrite(led, LOW); delay(30); } digitalWrite(led, last_state); } void flashRedGreen(uint8_t i) { uint8_t last_state_r; uint8_t last_state_g; last_state_r = digitalRead(LED_RED); last_state_g = digitalRead(LED_GRN); for (uint8_t j = 0; j < i; j++) { digitalWrite(LED_RED, LOW); digitalWrite(LED_GRN, HIGH); delay(75); analogWrite(LED_RED, LED_RED_BRIGHTNESS); digitalWrite(LED_GRN, LOW); delay(75); } digitalWrite(LED_RED, last_state_r); digitalWrite(LED_GRN, last_state_g); } void handle_leds() { static unsigned long next = millis(); switch (MODE) { case SCROLL: // solid red digitalWrite(LED_GRN, LOW); analogWrite(LED_RED, LED_RED_BRIGHTNESS); //digitalWrite(LED_RED, HIGH); break; case SNAPSHOT: // solid green digitalWrite(LED_GRN, HIGH); digitalWrite(LED_RED, LOW); break; case FS: // solid green digitalWrite(LED_RED, LOW); digitalWrite(LED_GRN, HIGH); break; case TUNER: // blink green if (millis() - next > 500) { next += 500; if(digitalRead(LED_GRN)){ digitalWrite(LED_GRN, LOW); }else{ digitalWrite(LED_GRN, HIGH); } } break; case LOOPER: switch (LPR_MODE) { case STOP: digitalWrite(LED_GRN, LOW); digitalWrite(LED_RED, LOW); break; case PLAY: digitalWrite(LED_GRN, HIGH); digitalWrite(LED_RED, LOW); break; case RECORD: digitalWrite(LED_GRN, LOW); analogWrite(LED_RED, LED_RED_BRIGHTNESS); break; case OVERDUB: // yellow digitalWrite(LED_GRN, HIGH); analogWrite(LED_RED, LED_RED_BRIGHTNESS); break; } break; } } void MyCCFunction(byte channel, byte number, byte value) { if(channel == 1){ //Serial.print("AMP SUB STARTED"); if(number == 20){ if(value == 127){ digitalWrite(AMP_RELAY,HIGH); }else{ digitalWrite(AMP_RELAY,LOW); } } } } void countStart(){ play_flag = 1; } void countContinue(){ play_flag = 1; } void countStop(){ play_flag = 0; digitalWrite(TAP_RELAY, LOW); tapCount = 0; counter = 0; } void clockHandler(){ if(play_flag == 1){ count(); Sync(); } } //sync and count function from midi tap tempo void Sync() { if(counter == 23) { counter = 0; } if((counter == 0) && (tapCount<= 3)){ digitalWrite(TAP_RELAY, HIGH); tapCount++; } if(counter == 6){ // this will set the duration of the tap digitalWrite(TAP_RELAY, LOW); } if (interval != prevInterval){ tapCount = 0; } counter++; prevInterval= interval; } void count(){ if(clickCounter >= 71){ //72(#clicks counted= 3 quarter notes) interval = timeElapsed/72; timeElapsed = 0; clickCounter = 0; } clickCounter++; }
×
×
  • Create New...