diff --git a/platformio.ini b/platformio.ini index 111ac9f..98678c2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,6 +12,4 @@ platform = teensy board = teensylc framework = arduino -lib_deps = - thomasfredericks/Bounce2@^2.71 build_flags = -D USB_MIDI -D TEENSY_OPT_FASTEST \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 675b1d6..3b5642e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,50 +1,38 @@ #include -#include #define MIDI_NAME {'P', 'i', 'n', 'g', 'b', 'o', 'a', 'r', 'd'} #define MIDI_NAME_LEN 9 -#define CHECK_PINS 9 +#define KEY_GROUP_NUM 9 #define KEY_PINS 6 -#define BOUNCE_TIME 5 +#define NUMBER_OF_KEYS 49 + +#define DEBOUNCE_TIMES 2 + #define POWER_SUPPLY_CHECK_PIN 13 -#define NUMBER_OF_KEYS 49 -#define SELF_DRIVE_INTERVAL 100 - -Bounce check_pins[CHECK_PINS] { - {14, BOUNCE_TIME}, // not KEYS1..6 - {15, BOUNCE_TIME}, // not KEYS7..12 - {16, BOUNCE_TIME}, // not KEYS13..18 - {17, BOUNCE_TIME}, // not KEYS19..24 - {18, BOUNCE_TIME}, // not KEYS25..30 - {19, BOUNCE_TIME}, // not KEYS31..36 - {20, BOUNCE_TIME}, // not KEYS37..42 - {21, BOUNCE_TIME}, // not KEYS43..48 - {22, BOUNCE_TIME} // not KEYS49 -}; +const uint8_t group_pins[KEY_GROUP_NUM] {14, 15, 16, 17, 18, 19, 20, 21, 22}; // not KEY0%6..not KEY5%6 -const unsigned char key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; +const uint8_t key_pins[KEY_PINS] {2, 3, 4, 5, 6, 7}; // Array of pressed keys (initially all 0) -bool keys_pressed[NUMBER_OF_KEYS]; +uint8_t keys_pressed[NUMBER_OF_KEYS]; // K1, K2, K3, K4, K5, K12, K13, K14, K15 -const unsigned char self_drive_pins[CHECK_PINS] {8, 9, 10, 11, 12, 26, 23, 24, 25}; -volatile unsigned char curr_self_drive_pin = 0; -IntervalTimer self_drive_timer = IntervalTimer(); +const uint8_t self_drive_pins[KEY_GROUP_NUM] {8, 9, 10, 11, 12, 26, 23, 24, 25}; +uint8_t current_self_drive_pin = 0; // Map the current array and pressed key to a MIDI note -unsigned char mapToMidi(char curr_arr, char key) { - unsigned char offset = (curr_arr >> 1) * 12; - // TODO: maybe we have to switch the notes and array offsets +uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) { + uint8_t offset = (active_key_group >> 1) * 12; + // case 3 and case 4 are swapped on purpose to reflect circuitry // Uneven offset are the upper octave, even the lower - if (curr_arr & 1) { + if (active_key_group & 1) { switch (key) { case 0: return offset + 42; // F#2 + offset case 1: return offset + 43; // G2 + offset case 2: return offset + 44; // G#2 + offset - case 3: return offset + 45; // A2 + offset - case 4: return offset + 46; // A#2 + offset + case 4: return offset + 45; // A2 + offset + case 3: return offset + 46; // A#2 + offset case 5: return offset + 47; // B2 + offset } } else { @@ -52,8 +40,8 @@ unsigned char mapToMidi(char curr_arr, char key) { case 0: return offset + 36; // C2 + offset case 1: return offset + 37; // C#2 + offset case 2: return offset + 38; // D2 + offset - case 3: return offset + 39; // D#2 + offset - case 4: return offset + 40; // E2 + offset + case 4: return offset + 39; // D#2 + offset + case 3: return offset + 40; // E2 + offset case 5: return offset + 41; // F2 + offset } } @@ -63,18 +51,19 @@ unsigned char mapToMidi(char curr_arr, char key) { } // Check if any of the array pins fell since last time -char findCurrentArrPin() { - for (unsigned char i = 0; i < CHECK_PINS; i++) { +int8_t getActiveKeyGroup() { + uint8_t active_groups = 0; + int8_t last_active_key_group = -1; + for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { // Update status - check_pins[i].update(); - // Check if the pin fell or is low - // ! inverted - if (check_pins[i].fell()) return i; + if (digitalReadFast(group_pins[i]) == LOW){ + last_active_key_group = (int8_t) i; + active_groups++; + } } - - // If none fell we should have enough time to see which one is low - for (unsigned char i = 0; i < CHECK_PINS; i++) { - if (check_pins[i].read() == LOW) return i; + + if (active_groups==1){ + return last_active_key_group; } // Default return @@ -84,75 +73,72 @@ char findCurrentArrPin() { // Set the next self drive pin FASTRUN void nextSelfDrivePin() { // Set the current pin to high - digitalWriteFast(self_drive_pins[curr_self_drive_pin], HIGH); + digitalWriteFast(self_drive_pins[current_self_drive_pin != 0 ? current_self_drive_pin - 1 : KEY_GROUP_NUM - 1], LOW); + digitalWriteFast(self_drive_pins[current_self_drive_pin], HIGH); // Set the next pin - curr_self_drive_pin = (curr_self_drive_pin + 1) % CHECK_PINS; -} - -// Interrupt for power supply check -FASTRUN void powerStateChanged() { - unsigned char state = digitalReadFast(POWER_SUPPLY_CHECK_PIN); - // ! inverted - if (state == LOW) { - curr_self_drive_pin = 0; - self_drive_timer.begin(nextSelfDrivePin, SELF_DRIVE_INTERVAL); - } else { - self_drive_timer.end(); - } + current_self_drive_pin = (current_self_drive_pin + 1) % KEY_GROUP_NUM; } // Initial start function void setup() { // Set all in- and outputs - for (unsigned char i = 0; i < CHECK_PINS; i++) { - pinMode(check_pins[i].getPin(), INPUT); - pinMode(self_drive_pins[i], INPUT); + for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) { + pinMode(group_pins[i], INPUT); + pinMode(self_drive_pins[i], OUTPUT); } - for (unsigned char i = 0; i < KEY_PINS; i++) { + for (uint8_t i = 0; i < KEY_PINS; i++) { pinMode(key_pins[i], INPUT); } pinMode(POWER_SUPPLY_CHECK_PIN, INPUT); - // Manual call, so we can set the initial state - powerStateChanged(); - // Setup interrupt for power supply - attachInterrupt(POWER_SUPPLY_CHECK_PIN, []() { while (true); }, CHANGE); } // Main loop void loop() { // Find active arr pin - char curr_arr = findCurrentArrPin(); + int8_t active_key_group = getActiveKeyGroup(); // If none is active, we do nothing, else we check the keys - if (curr_arr >= 0) { + if (active_key_group >= 0) { // Get all the key values ans send the MIDI message if needed - unsigned char value; + uint8_t value; - for (unsigned char i = 0; i < KEY_PINS; i++) { + for (uint8_t i = 0; i < KEY_PINS; i++) { + // due to the circuitry, there is one phantom note above + // the highest key constantly 'playing' + // but we don't need to scan that far anyway + if (active_key_group == KEY_GROUP_NUM-1 && i>0){ + break; + } value = digitalReadFast(key_pins[i]); // If the key is pressed, we send a MIDI message and set the entry in the array // ! inverted if (value == LOW) { // Check if the key is not already pressed - if (keys_pressed[curr_arr * 6 + i] == 0) { + if (keys_pressed[active_key_group * 6 + i] >= DEBOUNCE_TIMES) { // Send MIDI message - usbMIDI.sendNoteOn(mapToMidi(curr_arr, i), 127, 1); - // Set the entry in the array - keys_pressed[curr_arr * 6 + i] = 1; + usbMIDI.sendNoteOn(mapToMidi(active_key_group, i), 127, 1); } + + // Set the entry in the array + keys_pressed[active_key_group * 6 + i] += keys_pressed[active_key_group * 6 + i] < 0xFF ? 1 : 0; } else { // Check if the key is not already released - if (keys_pressed[curr_arr * 6 + i] == 1) { + if (keys_pressed[active_key_group * 6 + i] < DEBOUNCE_TIMES) { // Send MIDI message - usbMIDI.sendNoteOff(mapToMidi(curr_arr, i), 0, 1); - // Set the entry in the array - keys_pressed[curr_arr * 6 + i] = 0; + usbMIDI.sendNoteOff(mapToMidi(active_key_group, i), 0, 1); } + + // Set the entry in the array + keys_pressed[active_key_group * 6 + i] = 0; } } - } + } // MIDI Controllers should discard incoming MIDI messages. - while (usbMIDI.read()) { + while (usbMIDI.read()) {} + + // switch to next key group, if self powered + if (digitalReadFast(POWER_SUPPLY_CHECK_PIN) == LOW) { + nextSelfDrivePin(); } } \ No newline at end of file