/* Roll-a-tone Example Code SparkFun Electronics 2011 N.Poole This is some really awfully messy code that I created for the product video. It's essentially a mashup of the Musical Instrument Shield example code by Nathan Seidle and the PS/2mouse Library example found at: www.arduino.cc/playground/ComponentLib/Ps2mouse I left most of the original comments intact so it shouldn't be too difficult to pick it apart and figure out what the heck I was thinking. Roll the ball up and down to control the volume (velocity) of the notes, Roll side to side to play different notes, Press the buttons (Yellow and White wires pulled to Ground) to change instruments. Have fun! Make Music! Modify my code! Who Cares? */ #define MDATA 5 #define MCLK 6 #include NewSoftSerial mySerial(2, 3); //Soft TX on 3, we don't use RX in this code byte note = 0; //The MIDI note value to be played byte resetMIDI = 4; //Tied to VS1053 Reset line byte ledPin = 13; //MIDI traffic inidicator int instrument = 11; int lnote = 0; int vel = 0; void gohi(int pin) { pinMode(pin, INPUT); digitalWrite(pin, HIGH); } void golo(int pin) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } void mouse_write(char data) { char i; char parity = 1; // Serial.print("Sending "); // Serial.print(data, HEX); // Serial.print(" to mouse\n"); // Serial.print("RTS"); /* put pins in output mode */ gohi(MDATA); gohi(MCLK); delayMicroseconds(300); golo(MCLK); delayMicroseconds(300); golo(MDATA); delayMicroseconds(10); /* start bit */ gohi(MCLK); /* wait for mouse to take control of clock); */ while (digitalRead(MCLK) == HIGH) ; /* clock is low, and we are clear to send data */ for (i=0; i < 8; i++) { if (data & 0x01) { gohi(MDATA); } else { golo(MDATA); } /* wait for clock cycle */ while (digitalRead(MCLK) == LOW) ; while (digitalRead(MCLK) == HIGH) ; parity = parity ^ (data & 0x01); data = data >> 1; } /* parity */ if (parity) { gohi(MDATA); } else { golo(MDATA); } while (digitalRead(MCLK) == LOW) ; while (digitalRead(MCLK) == HIGH) ; /* stop bit */ gohi(MDATA); delayMicroseconds(50); while (digitalRead(MCLK) == HIGH) ; /* wait for mouse to switch modes */ while ((digitalRead(MCLK) == LOW) || (digitalRead(MDATA) == LOW)) ; /* put a hold on the incoming data. */ golo(MCLK); // Serial.print("done.\n"); } /* * Get a byte of data from the mouse */ char mouse_read(void) { char data = 0x00; int i; char bit = 0x01; // Serial.print("reading byte from mouse\n"); /* start the clock */ gohi(MCLK); gohi(MDATA); delayMicroseconds(50); while (digitalRead(MCLK) == HIGH) ; delayMicroseconds(5); /* not sure why */ while (digitalRead(MCLK) == LOW) /* eat start bit */ ; for (i=0; i < 8; i++) { while (digitalRead(MCLK) == HIGH) ; if (digitalRead(MDATA) == HIGH) { data = data | bit; } while (digitalRead(MCLK) == LOW) ; bit = bit << 1; } /* eat parity bit, which we ignore */ while (digitalRead(MCLK) == HIGH) ; while (digitalRead(MCLK) == LOW) ; /* eat stop bit */ while (digitalRead(MCLK) == HIGH) ; while (digitalRead(MCLK) == LOW) ; /* put a hold on the incoming data. */ golo(MCLK); // Serial.print("Recvd data "); // Serial.print(data, HEX); // Serial.print(" from mouse\n"); return data; } void mouse_init() { gohi(MCLK); gohi(MDATA); // Serial.print("Sending reset to mouse\n"); mouse_write(0xff); mouse_read(); /* ack byte */ // Serial.print("Read ack byte1\n"); mouse_read(); /* blank */ mouse_read(); /* blank */ // Serial.print("Sending remote mode code\n"); mouse_write(0xf0); /* remote mode */ mouse_read(); /* ack */ // Serial.print("Read ack byte2\n"); delayMicroseconds(100); } void setup() { Serial.begin(9600); mouse_init(); //Setup soft serial for MIDI control mySerial.begin(31250); //Reset the VS1053 pinMode(resetMIDI, OUTPUT); digitalWrite(resetMIDI, LOW); delay(100); digitalWrite(resetMIDI, HIGH); delay(100); } /* * get a reading from the mouse and report it back to the * host via the serial line. */ void loop() { char mstat; char mx; char my; /* get a reading from the mouse */ mouse_write(0xeb); /* give me data! */ mouse_read(); /* ignore ack */ mstat = mouse_read(); mx = mouse_read(); my = mouse_read(); /* send the data back up */ Serial.print(mstat, DEC); Serial.print("\tX="); Serial.print(mx, DEC); Serial.print("\tY="); Serial.print(my, DEC); Serial.println(); delay(20); /* twiddle */ talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume to near max (127) //Demo Basic MIDI instruments, GM1 //================================================================= talkMIDI(0xB0, 0, 0x00); //Default bank GM1 talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command note = map(mx, -127, 127, 30, 90); vel = map(my, -127, 127, 0, 120); if(lnote != note){ //Note on channel 1 (0x90), some note value (note), middle velocity (0x45): noteOn(0, note, vel); delay(50);} if(mstat == 9){ instrument--; talkMIDI(0xC0, instrument, 0);} if(mstat == 10){ instrument++; talkMIDI(0xC0, instrument, 0);} lnote = note; } //Send a MIDI note-on message. Like pressing a piano key //channel ranges from 0-15 void noteOn(byte channel, byte note, byte attack_velocity) { talkMIDI( (0x90 | channel), note, attack_velocity); } //Send a MIDI note-off message. Like releasing a piano key void noteOff(byte channel, byte note, byte release_velocity) { talkMIDI( (0x80 | channel), note, release_velocity); } //Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or that data values are less than 127 void talkMIDI(byte cmd, byte data1, byte data2) { digitalWrite(ledPin, HIGH); mySerial.print(cmd, BYTE); mySerial.print(data1, BYTE); //Some commands only have one data byte. All cmds less than 0xBn have 2 data bytes //(sort of: http://253.ccarh.org/handout/midiprotocol/) if( (cmd & 0xF0) <= 0xB0) mySerial.print(data2, BYTE); digitalWrite(ledPin, LOW); }