Compare commits

...

8 Commits

Author SHA1 Message Date
Daniel
2cd7817d5c
Make it work 2023-12-16 13:03:03 +01:00
262ecbd928 Formatting 2023-12-16 12:58:34 +01:00
Oliver Parczyk
7bf222228e Fix self driving mode
There was no need to have a timer do the key group switching routine. Not only would that have to be syncronized to the main loop somehow (or run very slowly),
it's also quite an overhead to keep track of.

Just switching to the next key group after we're done scanning the current one, syncronously, works far better (and faster!).
2023-12-16 12:03:25 +01:00
Oliver Parczyk
4c1658a3c6 Fix pinmode of self driving pins 2023-12-16 11:57:52 +01:00
Oliver Parczyk
54d685f62b Fix wrong order of keys 2023-12-16 11:56:37 +01:00
Oliver Parczyk
0c13d4da75 Fix constantly playing note out of range 2023-12-16 11:55:02 +01:00
Oliver Parczyk
030f2a39ae Remove debounce library dependency
Debouncing, the way it was done may have been appropriate for human input, but is wholly inadequate for the sequential scanning of the host keyboard IC.
It is however neccessary to provide something like debounce, because the teensy and host IC aren't syncronized.
2023-12-16 11:53:16 +01:00
Oliver Parczyk
58bdf0aac7 Refactor variable names and types
Neccessary because on ARM 'char' != int8_t but uint_8
Just declaring what know you want makes this far less confusing.
see https://en.cppreference.com/w/cpp/language/types
2023-12-16 11:18:51 +01:00
2 changed files with 62 additions and 78 deletions

View File

@ -12,6 +12,4 @@
platform = teensy platform = teensy
board = teensylc board = teensylc
framework = arduino framework = arduino
lib_deps =
thomasfredericks/Bounce2@^2.71
build_flags = -D USB_MIDI -D TEENSY_OPT_FASTEST build_flags = -D USB_MIDI -D TEENSY_OPT_FASTEST

View File

@ -1,50 +1,38 @@
#include <Arduino.h> #include <Arduino.h>
#include <Bounce2.h>
#define MIDI_NAME {'P', 'i', 'n', 'g', 'b', 'o', 'a', 'r', 'd'} #define MIDI_NAME {'P', 'i', 'n', 'g', 'b', 'o', 'a', 'r', 'd'}
#define MIDI_NAME_LEN 9 #define MIDI_NAME_LEN 9
#define CHECK_PINS 9 #define KEY_GROUP_NUM 9
#define KEY_PINS 6 #define KEY_PINS 6
#define BOUNCE_TIME 5 #define NUMBER_OF_KEYS 49
#define DEBOUNCE_TIMES 2
#define POWER_SUPPLY_CHECK_PIN 13 #define POWER_SUPPLY_CHECK_PIN 13
#define NUMBER_OF_KEYS 49 const uint8_t group_pins[KEY_GROUP_NUM] {14, 15, 16, 17, 18, 19, 20, 21, 22};
#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
};
// not KEY0%6..not KEY5%6 // 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) // 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 // 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}; const uint8_t self_drive_pins[KEY_GROUP_NUM] {8, 9, 10, 11, 12, 26, 23, 24, 25};
volatile unsigned char curr_self_drive_pin = 0; uint8_t current_self_drive_pin = 0;
IntervalTimer self_drive_timer = IntervalTimer();
// Map the current array and pressed key to a MIDI note // Map the current array and pressed key to a MIDI note
unsigned char mapToMidi(char curr_arr, char key) { uint8_t mapToMidi(uint8_t active_key_group, uint8_t key) {
unsigned char offset = (curr_arr >> 1) * 12; uint8_t offset = (active_key_group >> 1) * 12;
// TODO: maybe we have to switch the notes and array offsets // case 3 and case 4 are swapped on purpose to reflect circuitry
// Uneven offset are the upper octave, even the lower // Uneven offset are the upper octave, even the lower
if (curr_arr & 1) { if (active_key_group & 1) {
switch (key) { switch (key) {
case 0: return offset + 42; // F#2 + offset case 0: return offset + 42; // F#2 + offset
case 1: return offset + 43; // G2 + offset case 1: return offset + 43; // G2 + offset
case 2: return offset + 44; // G#2 + offset case 2: return offset + 44; // G#2 + offset
case 3: return offset + 45; // A2 + offset case 4: return offset + 45; // A2 + offset
case 4: return offset + 46; // A#2 + offset case 3: return offset + 46; // A#2 + offset
case 5: return offset + 47; // B2 + offset case 5: return offset + 47; // B2 + offset
} }
} else { } else {
@ -52,8 +40,8 @@ unsigned char mapToMidi(char curr_arr, char key) {
case 0: return offset + 36; // C2 + offset case 0: return offset + 36; // C2 + offset
case 1: return offset + 37; // C#2 + offset case 1: return offset + 37; // C#2 + offset
case 2: return offset + 38; // D2 + offset case 2: return offset + 38; // D2 + offset
case 3: return offset + 39; // D#2 + offset case 4: return offset + 39; // D#2 + offset
case 4: return offset + 40; // E2 + offset case 3: return offset + 40; // E2 + offset
case 5: return offset + 41; // F2 + 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 // Check if any of the array pins fell since last time
char findCurrentArrPin() { int8_t getActiveKeyGroup() {
for (unsigned char i = 0; i < CHECK_PINS; i++) { uint8_t active_groups = 0;
int8_t last_active_key_group = -1;
for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) {
// Update status // Update status
check_pins[i].update(); if (digitalReadFast(group_pins[i]) == LOW){
// Check if the pin fell or is low last_active_key_group = (int8_t) i;
// ! inverted active_groups++;
if (check_pins[i].fell()) return i; }
} }
// If none fell we should have enough time to see which one is low if (active_groups==1){
for (unsigned char i = 0; i < CHECK_PINS; i++) { return last_active_key_group;
if (check_pins[i].read() == LOW) return i;
} }
// Default return // Default return
@ -84,75 +73,72 @@ char findCurrentArrPin() {
// Set the next self drive pin // Set the next self drive pin
FASTRUN void nextSelfDrivePin() { FASTRUN void nextSelfDrivePin() {
// Set the current pin to high // 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 // Set the next pin
curr_self_drive_pin = (curr_self_drive_pin + 1) % CHECK_PINS; current_self_drive_pin = (current_self_drive_pin + 1) % KEY_GROUP_NUM;
}
// 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();
}
} }
// Initial start function // Initial start function
void setup() { void setup() {
// Set all in- and outputs // Set all in- and outputs
for (unsigned char i = 0; i < CHECK_PINS; i++) { for (uint8_t i = 0; i < KEY_GROUP_NUM; i++) {
pinMode(check_pins[i].getPin(), INPUT); pinMode(group_pins[i], INPUT);
pinMode(self_drive_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(key_pins[i], INPUT);
} }
pinMode(POWER_SUPPLY_CHECK_PIN, 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 // Main loop
void loop() { void loop() {
// Find active arr pin // 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 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 // 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]); value = digitalReadFast(key_pins[i]);
// If the key is pressed, we send a MIDI message and set the entry in the array // If the key is pressed, we send a MIDI message and set the entry in the array
// ! inverted // ! inverted
if (value == LOW) { if (value == LOW) {
// Check if the key is not already pressed // 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 // Send MIDI message
usbMIDI.sendNoteOn(mapToMidi(curr_arr, i), 127, 1); usbMIDI.sendNoteOn(mapToMidi(active_key_group, i), 127, 1);
// Set the entry in the array
keys_pressed[curr_arr * 6 + i] = 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 { } else {
// Check if the key is not already released // 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 // Send MIDI message
usbMIDI.sendNoteOff(mapToMidi(curr_arr, i), 0, 1); usbMIDI.sendNoteOff(mapToMidi(active_key_group, i), 0, 1);
// Set the entry in the array
keys_pressed[curr_arr * 6 + i] = 0;
} }
// Set the entry in the array
keys_pressed[active_key_group * 6 + i] = 0;
} }
} }
} }
// MIDI Controllers should discard incoming MIDI messages. // 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();
} }
} }