This repository has been archived by the owner on Oct 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
P150_Project.ino
126 lines (100 loc) · 3.35 KB
/
P150_Project.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "types.h"
// Teensy pins for the shift registers.
const int clockPin = 19;
const int dataPin = 21;
// Propagation delay in microseconds.
// This is the shorted value I was able to use while still having good readings.
const int propDelay = 3;
// The interval between the first and second switch while hitting keys with the
// highest velocity.
const float shortestInterval = 2000.0;
// Every time the interval between the first and second switch doubles, lower
// the midi velocity by this much:
const int velocityAttenuation = 20;
// Keep track of state.
Key keys[88];
bool pedalState;
void setup() {
// Initialize column pins.
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
// The sustain pedal gets a dedicated pin.
pinMode(12, INPUT_PULLUP);
// Initialize the pins for the shift register that manages rows.
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
Serial.begin(9600);
delay(500);
// Init keys
for ( int key = 0; key < 88; key++) {
keys[key].midi_note = 21 + key;
keys[key].t = 0;
keys[key].state = KEY_IS_UP;
}
}
void loop() {
// Send a "ground" through the shift registers.
digitalWrite(clockPin, LOW);
delayMicroseconds(propDelay);
digitalWrite(dataPin, LOW);
delayMicroseconds(propDelay);
digitalWrite(clockPin, HIGH);
delayMicroseconds(propDelay);
// Afterwards, don't send any ground.
digitalWrite(dataPin, HIGH);
for (int row = 0; row < 15; row++) {
for (int col = 0; col < 6; col++) {
// (14 - row) because I wired things backwards.
// *6 because there are 6 columns in each matrix row
// -2 because the first row is incomplete
// (otherwise there would be 90 keys, not 88)
int key_index = (14 - row) * 6 + col - 2;
bool switchA = !digitalRead(col);
bool switchB = !digitalRead(col + 6);
if (switchA) {
if (switchB && keys[key_index].state == KEY_IS_GOING_DOWN) {
keys[key_index].state = KEY_IS_DOWN;
unsigned long t = micros() - keys[key_index].t;
int velocity = 127 - log(t/shortestInterval)/log(2) * velocityAttenuation;
if (velocity < 0) {
velocity = 0;
}
usbMIDI.sendNoteOn(keys[key_index].midi_note, velocity, 0);
}
if (!switchB) {
if (keys[key_index].state == KEY_IS_UP) {
keys[key_index].state = KEY_IS_GOING_DOWN;
keys[key_index].t = micros();
}
else if (keys[key_index].state == KEY_IS_DOWN) {
keys[key_index].state = KEY_IS_GOING_UP;
}
}
}
else if (keys[key_index].state != KEY_IS_UP) {
keys[key_index].state = KEY_IS_UP;
usbMIDI.sendNoteOff(keys[key_index].midi_note, 127, 0);
}
}
// Move values in the shift register.
digitalWrite(clockPin, LOW);
delayMicroseconds(propDelay);
digitalWrite(clockPin, HIGH);
delayMicroseconds(propDelay);
}
bool pedalPressed = !digitalRead(12);
if (pedalPressed != pedalState) {
usbMIDI.sendControlChange(64, (pedalPressed ? 127 : 0), 0);
pedalState = pedalPressed;
}
}