mirror of
https://github.com/vale981/KSP-30-Hack
synced 2025-03-04 08:51:38 -05:00
233 lines
6.8 KiB
C++
233 lines
6.8 KiB
C++
#include <USB-MIDI.h>
|
|
#if DEBUG_SERIAL
|
|
#define Sprintln(...) (Serial.println(__VA_ARGS__))
|
|
#define Sprint(...) (Serial.print(__VA_ARGS__))
|
|
#else
|
|
#define Sprintln(...)
|
|
#define Sprint(...)
|
|
#endif
|
|
|
|
/*****************************************************************************/
|
|
/* Pins */
|
|
/*****************************************************************************/
|
|
|
|
#include "./pro_micro.h"
|
|
|
|
/*****************************************************************************/
|
|
/* Convenience */
|
|
/*****************************************************************************/
|
|
constexpr int col_pins[] = {KD1, KD2, KD3, KD4, KD5, KD6, KD7, KD8};
|
|
constexpr int num_col_pins = sizeof(col_pins) / sizeof(col_pins[0]);
|
|
constexpr int num_half_pins = num_col_pins / 2;
|
|
|
|
// first hit
|
|
constexpr int first_col[] = {KD1, KD2, KD3, KD4};
|
|
|
|
// second hit
|
|
constexpr int second_col[] = {KD5, KD6, KD7, KD8};
|
|
|
|
constexpr int selector_pins[] = {SA1, SA2, SA3, SA4, SA5};
|
|
constexpr int num_selector_pins =
|
|
sizeof(selector_pins) / sizeof(selector_pins[0]);
|
|
|
|
enum Range { LO = 0, MID, HI };
|
|
constexpr Range ranges[] = {Range::LO, Range::MID, Range::HI};
|
|
|
|
// rows in range
|
|
constexpr int rows[] = {8, 8, 6};
|
|
constexpr int range_offsets[] = {0, rows[1] * num_half_pins,
|
|
rows[0] * num_half_pins +
|
|
rows[1] * num_half_pins};
|
|
|
|
/*****************************************************************************/
|
|
/* Keys/Notes */
|
|
/*****************************************************************************/
|
|
constexpr int midi_base = 21;
|
|
constexpr int num_keys = 88;
|
|
constexpr midi::Channel channel = 1;
|
|
|
|
/*****************************************************************************/
|
|
/* Velocity */
|
|
/*****************************************************************************/
|
|
constexpr double min_velocity = 0.000001;
|
|
constexpr double max_velocity = 0.00015;
|
|
|
|
/*****************************************************************************/
|
|
/* Keyscanning */
|
|
/*****************************************************************************/
|
|
|
|
void select_range(Range range) {
|
|
switch (range) {
|
|
case Range::LO:
|
|
digitalWrite(RS1, LOW);
|
|
digitalWrite(RS2, LOW);
|
|
break;
|
|
|
|
case Range::MID:
|
|
digitalWrite(RS1, HIGH);
|
|
digitalWrite(RS2, LOW);
|
|
break;
|
|
|
|
case Range::HI:
|
|
digitalWrite(RS1, LOW);
|
|
digitalWrite(RS2, HIGH);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void select_row(int row) {
|
|
digitalWrite(SEL_A, row & 1);
|
|
|
|
row >>= 1;
|
|
digitalWrite(SEL_B, row & 1);
|
|
|
|
row >>= 1;
|
|
digitalWrite(SEL_C, row & 1);
|
|
}
|
|
|
|
// UNUSED
|
|
/* int scan_row(bool second) { */
|
|
/* const int (&pins)[num_half_pins] = second ? second_col : first_col; */
|
|
|
|
/* for(int i= 0; i < num_half_pins; i++) { */
|
|
/* if (!digitalRead(pins[i])) */
|
|
/* return i; */
|
|
/* } */
|
|
|
|
/* return -1; */
|
|
/* } */
|
|
|
|
int get_midi_note(Range range, int row, int col) {
|
|
return midi_base + row * num_half_pins + col + range_offsets[range];
|
|
}
|
|
|
|
char midi_velocity(double velocity) {
|
|
return constrain(
|
|
(constrain(velocity, min_velocity, max_velocity) - min_velocity) /
|
|
(max_velocity - min_velocity) * 127,
|
|
1, 127);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* State */
|
|
/*****************************************************************************/
|
|
unsigned long S1[num_keys]; // timer value for first hit or 0
|
|
bool S2[num_keys]; // whether key is pressed
|
|
bool SSTE_PRESSED = false;
|
|
|
|
USBMIDI_CREATE_DEFAULT_INSTANCE();
|
|
|
|
void setup() {
|
|
/***************************************************************************/
|
|
/* Serial */
|
|
/***************************************************************************/
|
|
#if DEBUG_SERIAL
|
|
Serial.begin(115200);
|
|
#endif
|
|
|
|
/***************************************************************************/
|
|
/* Pins */
|
|
/***************************************************************************/
|
|
for (int i = 0; i < num_col_pins; i++) {
|
|
pinMode(col_pins[i], INPUT_PULLUP);
|
|
}
|
|
|
|
for (int i = 0; i < num_selector_pins; i++) {
|
|
pinMode(selector_pins[i], OUTPUT);
|
|
}
|
|
|
|
for (int i = 0; i < num_keys; i++) {
|
|
S2[i] = false;
|
|
}
|
|
|
|
// Pedal
|
|
pinMode(SSTE, INPUT_PULLUP);
|
|
|
|
digitalWrite(RS1, LOW);
|
|
digitalWrite(RS2, LOW);
|
|
digitalWrite(SEL_A, LOW);
|
|
digitalWrite(SEL_B, LOW);
|
|
digitalWrite(SEL_C, LOW);
|
|
|
|
/***************************************************************************/
|
|
/* Midi */
|
|
/***************************************************************************/
|
|
MIDI.begin();
|
|
Sprintln("Keyboard ready.");
|
|
}
|
|
|
|
void send_note_down(int key, double velocity) {
|
|
Sprint("Key DOWN: ");
|
|
Sprint(key);
|
|
Sprint(" ");
|
|
Sprintln(midi_velocity(velocity), DEC);
|
|
MIDI.sendNoteOn(midi_base + key, midi_velocity(velocity), 1);
|
|
}
|
|
|
|
void send_note_up(int key) {
|
|
Sprint("Key UP: ");
|
|
Sprintln(key);
|
|
MIDI.sendNoteOff(midi_base + key, 55, 1);
|
|
}
|
|
|
|
void send_pedal(bool down) {
|
|
if (down) {
|
|
Sprintln("SSTE DOWN");
|
|
MIDI.sendControlChange(64, 127, 1);
|
|
} else {
|
|
Sprintln("SSTE UP");
|
|
MIDI.sendControlChange(64, 0, 1);
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
int key = 0;
|
|
|
|
// keys
|
|
for (const auto range : ranges) {
|
|
select_range(range);
|
|
|
|
for (int row = 0; row < rows[range]; row++) {
|
|
select_row(row);
|
|
|
|
// read rows
|
|
for (int i = 0; i < num_half_pins; i++) {
|
|
const bool s1_was_triggered = !(S1[key] == 0);
|
|
if (!digitalRead(first_col[i])) { // key pressed
|
|
if (!s1_was_triggered) { // has not been depreesed before
|
|
S1[key] = micros();
|
|
}
|
|
|
|
// look for second fire
|
|
const bool s2_was_triggered = S2[key];
|
|
if (!digitalRead(second_col[i])) { // stage 2 pressed
|
|
if (!s2_was_triggered) {
|
|
S2[key] = true;
|
|
|
|
auto velocity = 1 / static_cast<double>(micros() - S1[key]);
|
|
send_note_down(key, velocity);
|
|
}
|
|
} else if (s2_was_triggered) { // stage 2 released
|
|
S2[key] = false;
|
|
send_note_up(key);
|
|
}
|
|
} else if (s1_was_triggered) { // s1 released
|
|
S1[key] = 0;
|
|
|
|
if (S2[key]) {
|
|
S2[key] = false;
|
|
send_note_up(key);
|
|
}
|
|
}
|
|
|
|
key++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// pedals
|
|
if (!digitalRead(SSTE) != SSTE_PRESSED) {
|
|
SSTE_PRESSED = !SSTE_PRESSED;
|
|
send_pedal(SSTE_PRESSED);
|
|
}
|
|
}
|