Skip to content

Instantly share code, notes, and snippets.

@codetinkerhack
Last active June 7, 2020 16:35
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save codetinkerhack/4585458 to your computer and use it in GitHub Desktop.
Save codetinkerhack/4585458 to your computer and use it in GitHub Desktop.
Arduino based Velocity sensitive Midi keyboard with Aftertouch
// Pin Definitions
// Rows are connected to Digital
const int rowPin[] = { 6, 7, 8, 5 };
// FSRs connected to Analog
const int fsrPin[] = { 2, 3, 4, 5 };
// The 74HC595 uses a serial communication
// link which has three pins
const int clock = 12;
const int latch = 13;
const int data = 11;
int keyToMidiMap[32];
boolean keyPressed[32];
int noteChannelPressed[4][64];
int notesChannel[4] = { 0, 0, 0, 0 };
// use prepared bit vectors instead of shifting bit left everytime
int bits[] = { B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000 };
int fsrValue[4];
unsigned long currentMillis;
unsigned long previousMillisChannel[4] = { 0, 0, 0, 0 };
// miliseconds delay before aftertouch sent
unsigned long expressionDelay=1000;
// 74HC595 shift to next column
void scanColumn(int value) {
digitalWrite(latch, LOW); //Pulls the chips latch low
shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
digitalWrite(latch, HIGH); //Pulls the latch high displaying the data
}
void setup() {
// Map scan matrix buttons/keys to actual Midi note number. Lowest num 41 corresponds to F MIDI note.
keyToMidiMap[0] = 48;
keyToMidiMap[1] = 41;
keyToMidiMap[2] = 42;
keyToMidiMap[3] = 43;
keyToMidiMap[4] = 44;
keyToMidiMap[5] = 45;
keyToMidiMap[6] = 46;
keyToMidiMap[7] = 47;
keyToMidiMap[8] = 56;
keyToMidiMap[1 + 8] = 49;
keyToMidiMap[2 + 8] = 50;
keyToMidiMap[3 + 8] = 51;
keyToMidiMap[4 + 8] = 52;
keyToMidiMap[5 + 8] = 53;
keyToMidiMap[6 + 8] = 54;
keyToMidiMap[7 + 8] = 55;
keyToMidiMap[16] = 64;
keyToMidiMap[1 + 16] = 57;
keyToMidiMap[2 + 16] = 58;
keyToMidiMap[3 + 16] = 59;
keyToMidiMap[4 + 16] = 60;
keyToMidiMap[5 + 16] = 61;
keyToMidiMap[6 + 16] = 62;
keyToMidiMap[7 + 16] = 63;
keyToMidiMap[24] = 72;
keyToMidiMap[1 + 24] = 65;
keyToMidiMap[2 + 24] = 66;
keyToMidiMap[3 + 24] = 67;
keyToMidiMap[4 + 24] = 68;
keyToMidiMap[5 + 24] = 69;
keyToMidiMap[6 + 24] = 70;
keyToMidiMap[7 + 24] = 71;
// setup pins output/input mode
pinMode(data, OUTPUT);
pinMode(clock, OUTPUT);
pinMode(latch, OUTPUT);
pinMode(rowPin[0], INPUT);
pinMode(rowPin[1], INPUT);
pinMode(rowPin[2], INPUT);
pinMode(rowPin[3], INPUT);
Serial.begin(31250);
delay(1000);
}
void loop() {
currentMillis = millis();
getNote();
sendChannelExpression();
sendChannelNotes();
}
void sendChannelExpression() {
for (int c = 0; c < 4; c++) {
if (currentMillis - previousMillisChannel[c] > expressionDelay) {
midiChannelExpression(c, fsrValue[c]);
}
}
}
void readChannelPressure(int channel) {
int sensor = analogRead(fsrPin[channel]);
if (sensor > 0) {
fsrValue[channel] = map(sensor, 0, 900, 10, 127); //log(sensor2)*30+abs(sensor2);
}
}
void sendChannelNotes() {
for (int i = 0; i < 4; i++) {
readChannelPressure(i);
if (notesChannel[i] > 0 && (currentMillis > previousMillisChannel[i])) {
for (int t = 0; t < notesChannel[i]; t++) {
if (keyPressed[noteChannelPressed[i][t]] == true)
noteOn(i, keyToMidiMap[noteChannelPressed[i][t]], fsrValue[i]);
}
notesChannel[i] = 0;
}
}
}
void getNote() {
for (int i = 0; i < 8; i++) {
scanColumn(bits[i]);
for (int t = 0; t < 4; t++) {
int groupValue = digitalRead(rowPin[t]);
// key pressed
if (groupValue != 0 && !keyPressed[8 * t + i]) {
keyPressed[8 * t + i] = true;
// put the note into buffer
previousMillisChannel[t] = currentMillis;
noteChannelPressed[t][notesChannel[t]] = 8 * t + i;
notesChannel[t]++;
}
// key released
if (groupValue == 0 && keyPressed[8 * t + i]) {
keyPressed[8 * t + i] = false;
noteOn(t, keyToMidiMap[8 * t + i], 0);
}
}
}
}
void noteOn(int channel, int pitch, int velocity) {
command(0x90 + channel, pitch, velocity);
}
void midiChannelExpression(int channel, int value) {
// Modulation wheel effect
command(0xB0 + channel, 0x01, value);
}
void command(int cmd, int value1, int value2) {
Serial.write(cmd);
Serial.write(value1);
Serial.write(value2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment