From 5a3783d948267cb0d0c26d3092ed8245e32b08ff Mon Sep 17 00:00:00 2001 From: Steve Gilissen Date: Tue, 1 Jul 2025 21:20:19 +0200 Subject: [PATCH] Add MIDI panic function --- purrChestrion-arduino/gfx.h | 9 ++ purrChestrion-arduino/gfx_src/panic.aseprite | Bin 0 -> 403 bytes purrChestrion-arduino/gfx_src/panic.bmp | Bin 0 -> 1462 bytes .../purrChestrion-arduino.ino | 137 +++++++++++++----- 4 files changed, 111 insertions(+), 35 deletions(-) create mode 100644 purrChestrion-arduino/gfx_src/panic.aseprite create mode 100644 purrChestrion-arduino/gfx_src/panic.bmp diff --git a/purrChestrion-arduino/gfx.h b/purrChestrion-arduino/gfx.h index 0b8cbbd..6e937bd 100644 --- a/purrChestrion-arduino/gfx.h +++ b/purrChestrion-arduino/gfx.h @@ -63,4 +63,13 @@ const unsigned char savetorom [] PROGMEM = { 0x00, 0x05, 0x55, 0x54, 0x00, 0x0f, 0xff, 0xfe, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x8c, 0x00, 0x02, 0x01, 0xcd, 0x89, 0xb2, 0xbf, 0xed, 0x55, 0x54, 0x5f, 0xed, 0x95, 0x14, 0x01, 0xcd, 0x49, 0x12, 0x01, 0x8c, 0x00, 0x02, 0x01, 0x0c, 0x00, 0x02, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x05, 0x55, 0x54 +}; + +// 'panic', 32x12px +#define ICONPANIC_WIDTH 32 +#define ICONPANIC_HEIGHT 12 +const unsigned char iconpanic [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01, 0x8e, 0x38, 0xc9, 0x4d, 0x91, 0x25, 0x29, 0x51, + 0xa4, 0xa5, 0x2d, 0x51, 0xa4, 0xb9, 0xed, 0x51, 0xa0, 0xa1, 0x2b, 0x51, 0xa4, 0xa1, 0x2b, 0x51, + 0x91, 0x21, 0x29, 0x51, 0x8e, 0x21, 0x29, 0x4d, 0x80, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff }; \ No newline at end of file diff --git a/purrChestrion-arduino/gfx_src/panic.aseprite b/purrChestrion-arduino/gfx_src/panic.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..bab81743ff0d84a2edfa3e996e83b87377624634 GIT binary patch literal 403 zcmbQt$iVPmDIlWQz`zI+WDo#CS^#07>Aya*fNf;~S|A3*>ej~%*u)k3o3K!T4Q8%Gd%fv^{)Qu zUS0VHN+6pQ_<3^fqYg4i0pqR2n})=4@1SA)(MPU3rX|0ub{6F(U&9kYr$JU}Rtr;)YlXOcazDY&2XM3@y_b zti$>l)C%u2q%F9~FzfI;2D4AU83LZpWH8v5#gI3}oIyX+n?c1ph{4jvh@r&Zo}nqh zfZ<_YG{gVd$qY}<#xwl6eVXC_|Njiz*Un~WuWMn*%F1L23X5duaw=mmGFros9Db8w zSM_xUuj%~^2KikO2aJ-VAut*O0}=wFgaCe5iHZW{fkuExkV+sSiXebYumDsXO&+WX zsv4pTt{= 57 && pitch <= 88) { + MCPOutput out = noteToMCP[pitch - 57]; + if (out.chip == 0) { + mcp1.digitalWrite(out.pin, HIGH); + } else if (out.chip == 1) { + mcp2.digitalWrite(out.pin, HIGH); + } + } + } + + // Flash LED on Note On + digitalWrite(LED_BUILTIN, HIGH); + ledOnTime = millis(); + ledActive = true; +} + +void handleNoteOff(byte channel, byte pitch, byte velocity) { + #if USE_PANIC + if (midiPanic) return; // suppress all notes during panic + #endif + + if (currentMidiChannel == MIDI_CHANNEL_OMNI || channel == currentMidiChannel) { + if (pitch >= 57 && pitch <= 88) { + MCPOutput out = noteToMCP[pitch - 57]; + if (out.chip == 0) { + mcp1.digitalWrite(out.pin, LOW); + } else if (out.chip == 1) { + mcp2.digitalWrite(out.pin, LOW); + } + } + } +} + +void checkMidiPanic() { + #if USE_PANIC + static bool lastButtonState = HIGH; + static unsigned long lastToggleTime = 0; + const unsigned long debounceDelay = 50; + + bool currentButtonState = digitalRead(PANIC_BUTTON); + + if (lastButtonState == HIGH && currentButtonState == LOW) { + unsigned long now = millis(); + if (now - lastToggleTime > debounceDelay) { + midiPanic = !midiPanic; + lastToggleTime = now; + + if (midiPanic) { + // Turn off all notes immediately + for (int i = 0; i < 32; i++) { + if (noteToMCP[i].chip == 0) { + mcp1.digitalWrite(noteToMCP[i].pin, LOW); + } else { + mcp2.digitalWrite(noteToMCP[i].pin, LOW); + } + } + } + + #if USE_OLED + updateOLED(); // Only update display when state changes + #endif + } + } + + lastButtonState = currentButtonState; + #endif +} + + + + void setup() { // Validate saved midi channel in EEPROM if (savedChannel <= 16) { @@ -175,6 +265,10 @@ void setup() { pinMode(ENCODER_CLK, INPUT_PULLUP); pinMode(ENCODER_DT, INPUT_PULLUP); #endif + + #if USE_PANIC + pinMode(PANIC_BUTTON, INPUT_PULLUP); + #endif // Midi Activity LED on Pin 13 (aka LED_BUILTIN) pinMode(LED_BUILTIN, OUTPUT); @@ -196,12 +290,18 @@ void setup() { updateOLED(); } + + void loop() { MIDI.read(); #if USE_ENCODER checkEncoder(); #endif + + #if USE_PANIC + checkMidiPanic(); + #endif // Save channel if change timeout has passed if (channelChanged && (millis() - lastChannelChangeTime >= saveDelay)) { @@ -228,37 +328,4 @@ void loop() { digitalWrite(LED_BUILTIN, LOW); ledActive = false; } -} - - -void handleNoteOn(byte channel, byte pitch, byte velocity) { - if (currentMidiChannel == MIDI_CHANNEL_OMNI || channel == currentMidiChannel) { - - if (pitch >= 57 && pitch <= 88) { - MCPOutput out = noteToMCP[pitch - 57]; - if (out.chip == 0) { - mcp1.digitalWrite(out.pin, HIGH); - } else if (out.chip == 1) { - mcp2.digitalWrite(out.pin, HIGH); - } - } - } - - // Flash LED on Note On - digitalWrite(LED_BUILTIN, HIGH); - ledOnTime = millis(); - ledActive = true; -} - -void handleNoteOff(byte channel, byte pitch, byte velocity) { - if (currentMidiChannel == MIDI_CHANNEL_OMNI || channel == currentMidiChannel) { - if (pitch >= 57 && pitch <= 88) { - MCPOutput out = noteToMCP[pitch - 57]; - if (out.chip == 0) { - mcp1.digitalWrite(out.pin, LOW); - } else if (out.chip == 1) { - mcp2.digitalWrite(out.pin, LOW); - } - } - } } \ No newline at end of file