/* MIDI-Host-Adapter (c)2023 H. Wirtz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #define DEBUG #define STROBE_TM 9 #define CLOCK_TM 8 #define DIO_TM 7 #define MIDI_CH_BIT3 3 #define MIDI_CH_BIT2 4 #define MIDI_CH_BIT1 5 #define MIDI_CH_BIT0 2 bool swap_nibbles = true; bool high_freq = false; #define BRIGHTNESS 6 #define INITIAL_MIDI_CHANNEL 1 #define BUTTON_DEBOUNCE_TIME_MS 150 #define BLINK_FREQUENCY_MS 500 #define EEPROM_ADDRESS 0x42 // Constructor object TM1638plus_Model2 tm(STROBE_TM, CLOCK_TM, DIO_TM, swap_nibbles, high_freq); elapsedMillis button_debounce_timer; elapsedMillis blink_timer; uint8_t actual_channel; uint8_t new_channel; void setup() { Serial.begin(9600); delay(50); #if defined(DEBUG) Serial.println(""); #endif tm.displayBegin(); tm.brightness(BRIGHTNESS); tm.DisplayStr("HLLOWRLD", 0); uint8_t tmp_channel = EEPROM.read(EEPROM_ADDRESS); if (tmp_channel & 0xf0 != 0xf0) { actual_channel = 1; #if defined(DEBUG) Serial.println("Setting channel to 1"); #endif } else { actual_channel = 0x0f & tmp_channel; #if defined(DEBUG) Serial.print("Reading channel from EEPROM: "); Serial.println(actual_channel, DEC); #endif } new_channel = actual_channel; pinMode(MIDI_CH_BIT3, OUTPUT); pinMode(MIDI_CH_BIT2, OUTPUT); pinMode(MIDI_CH_BIT1, OUTPUT); pinMode(MIDI_CH_BIT0, OUTPUT); SetMidiChannel(INITIAL_MIDI_CHANNEL); delay(200); tm.DisplayDecNum(actual_channel, 0, false, TMAlignTextRight); #if defined(DEBUG) Serial.println(""); #endif } void loop() { uint8_t button; button = tm.ReadKey16(); if (button > 0 && button != actual_channel && button_debounce_timer > BUTTON_DEBOUNCE_TIME_MS) { if (button != new_channel) { // Button pressed once #if defined(DEBUG) Serial.print("Button pressed once: "); Serial.println(button, DEC); #endif button_debounce_timer = 0; blink_timer = 0; new_channel = button; tm.DisplayDecNumNibble(new_channel, actual_channel, 0, false, TMAlignTextRight); } else { // Button pressed twice #if defined(DEBUG) Serial.print("Button pressed twice: "); Serial.println(button, DEC); #endif actual_channel = new_channel; EEPROM.update(EEPROM_ADDRESS, 0xf0 | actual_channel); SetMidiChannel(actual_channel); tm.DisplayDecNum(actual_channel, 0, false, TMAlignTextRight); } } if (actual_channel != new_channel) { if (blink_timer > BLINK_FREQUENCY_MS) { blink_timer = 0; tm.DisplayDecNum(actual_channel, 0, false, TMAlignTextRight); } else if (blink_timer > BLINK_FREQUENCY_MS / 2) { tm.DisplayDecNumNibble(new_channel, actual_channel, 0, false, TMAlignTextRight); } } } void SetMidiChannel(uint8_t channel) { if (channel < 1 || channel > 16) { #if defined(DEBUG) Serial.print("ERROR: MIDI channel number out of range: "); Serial.print(channel, DEC); #endif return; } #if defined(DEBUG) Serial.print("Setting MIDI channel to: "); Serial.print(channel, DEC); Serial.print(" ("); printBinary(--channel, 4); Serial.println(")"); #endif digitalWrite(MIDI_CH_BIT0, channel & 0x00); digitalWrite(MIDI_CH_BIT1, channel & 0x01); digitalWrite(MIDI_CH_BIT2, channel & 0x02); digitalWrite(MIDI_CH_BIT3, channel & 0x08); } #if defined(DEBUG) void printBinary(uint32_t value, uint8_t len) { for (uint8_t b = len; b > 0; --b) { Serial.print((char)('0' + ((value >> (b - 1)) & 1))); } } #endif