You might remember that some years ago, I found a discarded organ and brought it home. Well, it sat around for a year, then I converted it to MIDI, then I moved across the country and only brought the keyboards, and finally I re-built it as the proper single-row unit featured in the above video.
The keys are laid out as a generic matrix-style keyboard, with a column for every note in an octave (12 in total), and a row for each octave bank (up to ten, although only 8 are in use). Using a Barebones Arduino clone and a couple of I/O expander chips (PCF854AN) for extra digital pins, I was able to convert the old keyboard into a MIDI device. This version works fine, however the circuit is a bit extravagant- If I ever re-build it, I will use a 3-to-8 line decoder for the select lines, which should free up enough digital pins on the Arduino to be able to get rid of the I/O expander chips. Really, though, I would prefer to convert it into a velocity sensitive keyboard, so any further effort will be in that direction. Rough schematic and source code after the break.
// Sketch to convert an older electric organ (Eminent S20) into a MIDI instrument. // By Matt Mets, completed in 2009 // // This code is released into the public domain. Attribution is appreciated. // // MIDI source code from the ITP website: // http://itp.nyu.edu/physcomp/Labs/MIDIOutput #include <Wire.h> #define LEDpin 13 // Just the standard output LED #define volumePedal 1 // The analog input for the volume control char velocity; // Use the foot pedal to determine this // Define the MIDI channels that each instrument transmits on #define keyboardChannel 0 // Number of key banks to scan. There are eight 'normal' key banks, and 2 special ones. #define numKeyBanks 8 #define numKeysPerBank 12 // Lookup table, used to determine the select line to turn on to read the keys in that key bank. static char keyBankSelectLines[] = {2,3,4,5,6,7,8,11}; // Storage for the previous value of each bank of keys. There are 10 access lines, with a maximum of 12 inputs per line. // The 12 bits of data on each line are split into low and high banks. unsigned char noteStatesL[numKeyBanks]; unsigned char noteStatesH[numKeyBanks]; // Storage for the instrument data associated with each key. Must be filled in at startup. unsigned char noteChannels[numKeyBanks][numKeysPerBank]; unsigned char noteValues[numKeyBanks][numKeysPerBank]; // Initialize IO ports void setup() { // Setup the I2C bus (analog pins 4&5) in master mode. This bus is used to talk to the IO expander chips. Wire.begin(); // Set the serial port to the correct baud rate for MIDI Serial.begin(31250); // Set all initial note bank vales to 0 for (unsigned int i = 0; i < numKeyBanks; i++) { noteStatesL[i] = 0; noteStatesH[i] = 0; } pinMode(LEDpin, OUTPUT); // Status LED // Set all of the bank select lines to outputs for (unsigned char bankNo = 0; bankNo < numKeyBanks; bankNo++) { pinMode(keyBankSelectLines[bankNo], OUTPUT); } // Set up the instrument data for the keys // first off, clear everything. for (unsigned char bank = 0; bank < numKeyBanks; bank ++) { for (unsigned char key = 0; key < numKeysPerBank; key++) { noteChannels[bank][key] = 0; noteValues[bank][key] = 0; } } // The bottom half of the keyboard comprised of banks 4-6, starting at F unsigned char noteValue = 24; // Octave 2, C note for (unsigned char bank = 4; bank < 7; bank ++) { for (unsigned char key = 0; key < 12; key++) { noteChannels[bank][key] = keyboardChannel; noteValues[bank][key] = noteValue++; } } // The top keyboard row is comprised of banks 0-3, starting at F for (unsigned char bank = 0; bank < 4; bank ++) { for (unsigned char key = 0; key < 12; key++) { noteChannels[bank][key] = keyboardChannel; noteValues[bank][key] = noteValue++; } } // And one extra one on bank 9 note 1 noteChannels[7][1] = keyboardChannel; noteValues[7][1] = noteValue++; } // Send a MIDI command. // cmd is the command and channel (0x90 for channel 1 note on) // data1 is the note // data2 is the velocity void midiCommand(char cmd, char data1, char data2) { Serial.print(cmd, BYTE); Serial.print(data1, BYTE); Serial.print(data2, BYTE); } // Map an integer into a charater given a set range unsigned char mapInteger(int input, int min, int max) { return (((input - min)*255)/(max-min)); } // Main loop unsigned char newNoteStateL; unsigned char newNoteStateH; void loop() { // Read the velocity in // velocity = mapInteger(analogRead(volumePedal),400,900); velocity = 90; for (char bankNo = 0; bankNo < numKeyBanks; bankNo++) { digitalWrite(keyBankSelectLines[bankNo], HIGH); // Select the key bank Wire.requestFrom(0x38, 1); // Read the low data while (Wire.available()) { newNoteStateL = Wire.receive(); } Wire.requestFrom(0x39, 1); // Read the high data while (Wire.available()) { newNoteStateH = Wire.receive(); } digitalWrite(keyBankSelectLines[bankNo], LOW); // Deselect the key bank if (newNoteStateL != noteStatesL[bankNo]) { // Check if any notes in this bank are different char stateDelta = newNoteStateL ^ noteStatesL[bankNo]; for (unsigned char i = 0; i < 8; i++) { if ((stateDelta >> i) & 1) { if ((newNoteStateL >> i) & 1) { // Send a MIDI on message midiCommand(0x90 + noteChannels[bankNo][i], noteValues[bankNo][i], velocity); } else { // Send a MIDI off message midiCommand(0x80 + noteChannels[bankNo][i], noteValues[bankNo][i], velocity); } } } } if (newNoteStateH != noteStatesH[bankNo]) { // Check if any notes in this bank are different digitalWrite(LEDpin, HIGH); char stateDelta = newNoteStateH ^ noteStatesH[bankNo]; for (unsigned char i = 0; i < 8; i++) { if ((stateDelta >> i) & 1) { if ((newNoteStateH >> i) & 1) { // Send a MIDI on message midiCommand(0x90 + noteChannels[bankNo][i+8], noteValues[bankNo][i+8], velocity); } else { // Send a MIDI off message midiCommand(0x80 + noteChannels[bankNo][i+8], noteValues[bankNo][i+8], velocity); } } } } noteStatesL[bankNo] = newNoteStateL; noteStatesH[bankNo] = newNoteStateH; } }

That is really cool! I haven’t heard of these Arduino clone boards before. I was always under the impression that if I wanted to write embedded code I had to buy expensive PIC stuff.
Do you get everything required (not including your external circuitry of course) with that barebones kit? It’s impressively cheap!!! I hope I can get them in New Zealand =)
I’m gonna be writing some Linux games to run at my kids’ playcentre and kindergarten, and I love the idea of making a real cheap MIDI keyboard to make a musical game. Thank you for your post. It’s exactly what I was hunting for.
Hi Paddy! Thanks!
Sorry for the late reply. The barebones kit comes with just the parts to put together the board. I had to add a breadboard, keyboard electronics, and (most importantly) a usb-to-serial cable to get it to talk to the computer.
The barebonesboard worked well for me since I had it connected to an actual MIDI device. If you are going to have it permanently attached to a computer, you’ll need a way to get the MIDI data into the computer. I’d recommend getting a board with a built-in USB converter, so that you can connect to it using usb. Here are a couple i’ve used, one from seeed studio:
http://www.nkcelectronics.com/seeeduino-fully-assembled–arduino-compatible.html
Or maybe, if you want to put it together, the freeduino:
http://www.nkcelectronics.com/freeduino-arduino-diecimila-compatible-board-complete-kit.html
Of course, the regular Arduino is only around ~30, so you don’t save much using these ones
.