Kuk on the old forum provided the basics for MIDI In using the USART on Arduino: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258 (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1187962258) However, his version just lit some LEDs on the Note On commands.
That's boring. I coupled it with tone() to produce a square wave synth. I do have MIDI gear but no spare jacks (yet), so instead I routed MIDI over Serial using this awesome freeware. http://projectgus.github.com/hairless-midiserial/ (http://projectgus.github.com/hairless-midiserial/) Remember to match your baud rates.
Piezo buzzer on line 7. You can USB this with the midi-serial bridge OR use Kuk's schematic to add a midi in jack and control it via your favorite MIDI controller.
Using the comments as a guide, this stub can be built out into a full blown MIDI controlled synth.
Video to follow.
// A very simple MIDI synth.
// Greg Kennedy 2011
#include <avr/pgmspace.h>
#define statusLed 13
#define tonePin 7
// MIDI channel to answer to, 0x00 - 0x0F
#define myChannel 0x00
// set to TRUE and the device will respond to all channels
#define respondAllChannels false
// midi commands
#define MIDI_CMD_NOTE_OFF 0x80
#define MIDI_CMD_NOTE_ON 0x90
#define MIDI_CMD_KEY_PRESSURE 0xA0
#define MIDI_CMD_CONTROLLER_CHANGE 0xB0
#define MIDI_CMD_PROGRAM_CHANGE 0xC0
#define MIDI_CMD_CHANNEL_PRESSURE 0xD0
#define MIDI_CMD_PITCH_BEND 0xE0
// this is a placeholder: there are
// in fact real midi commands from F0-FF which
// are not channel specific.
// this simple synth will just ignore those though.
#define MIDI_CMD_SYSEX 0xF0
// a dummy "ignore" state for commands which
// we wish to ignore.
#define MIDI_IGNORE 0x00
// midi "state" - which data byte we are receiving
#define MIDI_STATE_BYTE1 0x00
#define MIDI_STATE_BYTE2 0x01
// MIDI note to frequency
// This isn't exact and may sound a bit detuned at lower notes, because
// the floating point values have been rounded to uint16.
// Based on A440 tuning.
// I would prefer to use the typedef for this (prog_uint16_t), but alas that triggers a gcc bug
// and does not put anything into the flash memory.
// Also note the limitations of tone() which at 16mhz specifies a minimum frequency of 31hz - in other words, notes below
// B0 will play at the wrong frequency since the timer can't run that slowly!
uint16_t frequency[128] PROGMEM = {8, 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 18, 19, 21, 22, 23, 24, 26, 28, 29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62, 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 117, 123, 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 4186, 4435, 4699, 4978, 5274, 5588, 5920, 5920, 6645, 7040, 7459, 7902, 8372, 8870, 9397, 9956, 10548, 11175, 11840, 12544};
//setup: declaring iputs and outputs and begin serial
void setup() {
pinMode(statusLed,OUTPUT); // declare the LED's pin as output
pinMode(tonePin,OUTPUT); // setup tone output pin
//start serial with midi baudrate 31250
// or 38400 for debugging (eg MIDI over serial from PC)
Serial.begin(31250);
// indicate we are ready to receive data!
digitalWrite(statusLed,HIGH);
}
//loop: wait for serial data
void loop () {
static byte note;
static byte lastCommand = MIDI_IGNORE;
static byte state;
static byte lastByte;
while (Serial.available()) {
// read the incoming byte:
byte incomingByte = Serial.read();
// Command byte?
if (incomingByte & 0b10000000) {
if (respondAllChannels ||
(incomingByte & 0x0F) == myChannel) { // See if this is our channel
lastCommand = incomingByte & 0xF0;
} else { // Not our channel. Ignore command.
lastCommand = MIDI_IGNORE;
}
state = MIDI_STATE_BYTE1; // Reset our state to byte1.
} else if (state == MIDI_STATE_BYTE1) { // process first data byte
if ( lastCommand==MIDI_CMD_NOTE_OFF )
{ // if we received a "note off", make sure that is what is currently playing
if (note == incomingByte) noTone(tonePin);
state = MIDI_STATE_BYTE2; // expect to receive a velocity byte
} else if ( lastCommand == MIDI_CMD_NOTE_ON ){ // if we received a "note on", we wait for the note (databyte)
lastByte=incomingByte; // save the current note
state = MIDI_STATE_BYTE2; // expect to receive a velocity byte
}
// implement whatever further commands you want here
} else { // process second data byte
if (lastCommand == MIDI_CMD_NOTE_ON) {
if (incomingByte != 0) {
note = lastByte;
tone(tonePin,(unsigned int)pgm_read_word(&frequency[note]));
} else if (note == lastByte) {
noTone(tonePin);
}
}
state = MIDI_STATE_BYTE1; // message data complete
// This should be changed for SysEx
}
}
}
http://www.youtube.com/watch?v=4fUH5rKpH78
Sound output begins at 1:10.
Nice work.
recall that you can built a frequency table by having one octave (octave 8) and divide those values by (1 << (8-octave))
Check this thread somewhere in the middle of page 1 - http://arduino.cc/forum/index.php?topic=69163.0
I was playing around recently with converting midi to 3 tone AVR sounds and made a spreadsheet that looks like this http://jarv.org/files/midi-avr/arduino_all_piano_tones.html for match values that correspond to piano keys if it's helpful. (Here it is in open office format - http://jarv.org/files/midi-avr/arduino_all_piano_tones.ods )
arduinoroll? :smiley-roll:
Chip roll'd
Hi folks, I realize this is a very old topic but I wanted to give Greg Kennedy proper recognition for his work, which I am using.
I currently have this project simulated in Proteus and thought I'd share:
https://www.youtube.com/watch?v=jsKmlVharz0&feature=youtu.be
I plan to make a few changes to the Arduino code to make it multi-mode. Eventually I will be using it as an interrupter for a musical solid state Tesla coil. I just wanted to post here and thank Greg for his great work!
Regards,
Matt