I have a Glockenspiel I have been driving with hardware and thought it would be fun to play with an Arduino. Here's what I did. MIDI data comes from Power Tracks Pro Audio (or a keyboard) into a opto circuit. Output from the opto goes to a Software Serial port on the Arduino. This allows using the serial port for the Serial Monitor to debug this mess. I only look for MIDI commands to turn notes on or off and just ignore the rest. If I get a MIDI on, I read the note and the velocity, and convert the velocity to either on or off. There are only 24 notes, so I need three bytes of data sent to two 4x4 Logos Driver Shields. The driver shields powers the door bell magnets that are mounted on top of the bells. I don't use any librarys other than for the software serial port and the turnaround time to ring a bell is in the order of 2 milliseconds. I'm not a programmer but rather in the spirit of all of this, stole most of the code in the sketch below. A video off the glock is at this link
Enjoy.
Bill
#include <SoftwareSerial.h>
SoftwareSerial mySerial(5,6); // RX, TX
int value;
byte incomingByte;
byte note;
byte notes[24];
byte notetoplaynow;
byte velocity;
byte highByte;
byte lowByte;
byte lastByte;
unsigned long lasttimenotesent;
byte channel = 3; //set the MIDI channel here
void setup() {
mySerial.begin(31250);
Serial.begin(38400);
pinMode(5,INPUT);
pinMode(6,OUTPUT); //MIDI out not used
pinMode(7,OUTPUT); //Register Latch
pinMode(8,OUTPUT); //Register Latch
pinMode(9,OUTPUT); //Middle C light
pinMode(11,OUTPUT); //Register Input
pinMode(13,OUTPUT);} //Clock Pin for 4x4
void loop (){ //This only looks for on or off messages and the note and velocity MIDI 0 files do not work
incomingByte = mySerial.read();
//If the incomming byte just read was a command byte to turn a note on or off, read the next two bytes. Ignore everything else.
//1001nnnn (144=channel) is a turn on command byte. 1000nnnn (128) is a note off command where nnnn is the channel.
if (incomingByte== (127+16+channel) || incomingByte== (127+channel)){
note = mySerial.read();
lasttimenotesent=millis();
velocity = mySerial.read();
if (note>=57 && note<=80)playNote(note, velocity); } // Only play with useful notes
else if((millis()-lasttimenotesent)>1000) SendNotes(0, 0, 0); }//Don't leave notes stuck on
void playNote(byte note, byte velocity) {
value=LOW; //Set the note to either on or off regardless of velocity
if (velocity >10) value=HIGH;
notetoplaynow=note-57; //convert notetoplaynow to the right output register
if (value==HIGH) notes[notetoplaynow]=1; //notes[turn notetoplaynow] on
else if (value==LOW) notes[notetoplaynow]=0; //turn notes[notetoplaynow] off
byte lowByte = 0;
byte highByte = 0;
lastByte=0;
for ( byte i=0; i < 8; ++i )
{
lowByte |= (notes[i] << i ); //shift each note one register and keep oring them
highByte |= (notes[8+i] << i );
lastByte |= (notes[16+i] << i );
}
SendNotes(highByte, lowByte, lastByte); //go play the note
}
void SendNotes(byte highByte, byte lowByte, byte lastByte){
digitalWrite(7, LOW); // Prepares latch
digitalWrite(8, HIGH); // Deactivates master reset
shiftOut(11, 13, MSBFIRST, 0);
shiftOut(11, 13, MSBFIRST, lastByte);
shiftOut(11, 13, MSBFIRST, highByte); // shift data for OUT8-OUT15
shiftOut(11, 13, MSBFIRST, lowByte); // shift data for OUT0-OUT7
digitalWrite(7, HIGH);}