I'm starting with Arduino and I need developer a project for read and play a MIDI file in Arduino UNO.
If anypeople can help me, I'll make me feel very happy!
Best Regards
I'm starting with Arduino and I need developer a project for read and play a MIDI file in Arduino UNO.
If anypeople can help me, I'll make me feel very happy!
Best Regards
What do you mean by:-
read and play a MIDI file in Arduino UNO.
Where is the MIDI file to be stored and are you expecting the arduino to generate the sound?
If so you will be disappointed as the arduno can't produce many tones let alone anything approaching the MIDI GM sound set.
Although you cannot generate any quality audio with the UNO alone, it is possible to use something else - the midi shield!
http://www.skpang.co.uk/catalog/midi-shield-p-669.html
That should sort out the issues of bad sound quality.
Onions.
Thanks Grumpy_Mike and Oniosn
My ideia is: read a MIDI file maybe in my computer (I started with arduino in few weeks :S) and after play in piezo buzzer.
Example of OUTPUT: Play a melody with Arduino - YouTube
But I don't undertand how Interpret the Structure of MIDI file and if I can put my MIDI file in my computer.
Best Regards
You need something on your PC that reads MIDI files and outputs MIDI data. You also need a MIDI interface on your PC.
Then you need a MIDI interface on the Arduino and some software.
This project:-
http://www.thebox.myzen.co.uk/Hardware/Glockenspiel.html
fires solenoids when it receives MIDI data but you can modify it so that it generates a tone instead using the tone function.
But I don't understand how send the mid music
That is what I said at the start, you need an application on your computer to read a MIDI file and output it. There are lots around most MIDI musics apps allow you to do this.
Yes, I have timidity (it's works), but in tutorial don't show that send the MIDI file (messages).
# start ttymidi
ttymidi -s /dev/ttyUSB0 &
# start some ALSA compatible MIDI
# program (timidity, in this case)
timidity -iA &
# list available MIDI input clients
aconnect -i
# list available MIDI output clients
aconnect -o
# connect
aconnect 128:0 129:0
# ...where 128 and 129 are the client
# numbers for ttymidi and timidity,
# found with the commands above
But where is the MIDI file?
example: timidity abba.mid (with tty already connected com arduino)
and after my buzzer in arduino singing abba
Thanks
Timidity does not do anything with MIDI files, it acts as a conduit for you to put MIDI data through. You need an application that handles MIDI files and you point it at timidity an tell it to play the file.
Some idea how to do this?
I just want:
1 - Create a program in arduino that understand MIDI music file and reproduce.
2 - A way to put(send) MIDI file (messages, bytes, WHETEVER) to arduino.
3 - My piezo buzzer singing simple sound.
:S
I will go cry!!!
This is very difficulty
2 - A way to put(send) MIDI file (messages, bytes, WHETEVER) to arduino.
I use Garage Band, do you have that?
No well you need to get a program on your PC to do this. I am sorry but you haven't even said what operating system you are using.
You need to search and find a MIDI sequencer or other sort of file player.
I am not sure how many time I have to tell you?
This is very difficulty
You are making it difficult for your self by not reading my replies.
You are making it difficult for your self by not reading my replies.
Ok, sorry and thanks a lot about your help.
No well you need to get a program on your PC to do this. I am sorry but you haven't even said what operating system you are using.
My O.S. is ubuntu 11.10.
I thought that timitidy is a file player
[My O.S. is ubuntu 11.10](http://My O.S. is ubuntu 11.10)
That makes all the difference, sorry but I know little about Linux.
I thought that timitidy is a file player
The link you posted is for ttymidi, the first sentence says
ttymidi is a GPL-licensed program that allows external serial devices to interface with ALSA MIDI applications.
What you need is an ALSA MIDI applications, that is the thing that reads the file. Sorry but I can't find one for you due to my lack of experience with you operating system.
I just finished a project that might be do something similar to what you are asking here.
It takes a midi file (saved as musicxml) and allows you to select up to three parts that will be played on the arduino using the three timers.
This post has more information: http://jarv.org/2011/11/arduino-music-from-a-midi-file/
I also used this lib to protype creating a cheap musical greeting card using an attiny - http://jarv.org/2011/11/custom-musical-greeting-card-for-less-than-5/
How a midi conversion turned out for the SMB theme - PlayTune Mario - YouTube
Neat project! I'm trying to accomplish something similar. Specifically, I'd like the Arduino to output midi signals to my SparkFun Music Instrument Shield SparkFun Music Instrument Shield - DEV-10587 - SparkFun Electronics. Ideally, I'd like to combine some "canned" midi signals (including a variety of different drum loops) with some "live" signals generated from sensors. I had some success using the NewSoftSerial library to feed MIDI data to the shield.
Here's a sketch I did (based on one of the Sparkfun example sketches) which plays a simple beat. It reads the notes from characters in an array ("b" is kick, "t" is hi-hat, "k" is snare, space is a rest). It reads the delays attached to each note from another array, which in this case I've set up to allow swing on the 16ths.
#include <NewSoftSerial.h>
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 = 0;
int length;
char beat1[] = { "bbttktttbktbkttt"}; //Beat pattern #1
char beat2[] = { "bttbb b bb "}; //Beat pattern #2
bool tempoUp = 1;
float swing = 0.33; //0 is no swing; 0.33 should approximate typical "triplet" swing (2/3 + 1/3)
float beats[] = { 1+swing, 1-swing, 1+swing, 1-swing, 1+swing, 1-swing, 1+swing, 1-swing,
1+swing, 1-swing, 1+swing, 1-swing, 1+swing, 1-swing, 1+swing, 1-swing };
float tempo = 60;
void playNote(char note, float duration) {
char names[] = { 'b', 't', 'k' };
int tones[] = { 35, 42, 38 };
for (int i = 0; i < 3; i++) {
if (names[i] == note) {
Serial.print(note);
noteOn(0,tones[i],100);
// 16th note in ms 1 beat 1 min 60000 ms
// = 15000/tempo ------------ x ------- x ----------
// 4 16ths notes beats (bpm) min
delay(duration*15000/tempo); //duration adjustment allows for swing
noteOff(0,tones[i],0);
}
}
}
void playLoop(char beat[]) {
Serial.print("Swing:");
Serial.print(float(swing));
Serial.print(" ");
Serial.print("Tempo:");
Serial.print(int(tempo));
Serial.print(" ");
for (int i = 0; i < 16; i++) {
if (beat[i] == ' ') {
Serial.print("-");
delay(beats[i]*15000/tempo); //See above; each 16th's length in ms is 15000/tempo
} else {
playNote(beat[i], beats[i]);
}
delay(0);
if (tempoUp) { tempo *= 1.005; } //accelerando...
else { tempo /= 1.005; } //or decelerando
if (tempo > 150) { tempoUp = 0; } //slow down after 150 bpm
if (tempo < 50) { tempoUp = 1; } //speed up after 50 bpm
}
Serial.println("");
}
void setup() {
Serial.begin(57600);
//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);
}
void loop() {
talkMIDI(0xB0, 0x07, 50); //0xB0 is channel message, set channel volume to near max (127)
talkMIDI(0xB0, 0, 0x78); //Bank select drums
talkMIDI(0xC0, instrument, 0); //Select instrument; doesn't matter which for drums
playLoop(beat1);
playLoop(beat2);
for (int i = 0; i < 16; i++) { //Set swing for each pair in beats[]
if (i%2 == 0) { beats[i] = 1+swing; }
else { beats[i] = 1-swing; }
}
}
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}
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);
// Serial.write(cmd);
// Serial.write(data1);
mySerial.print(cmd, BYTE);
mySerial.print(data1, BYTE);
if( (cmd & 0xF0) <= 0xB0 || (cmd & 0xF0) == 0xE0)
// Serial.write(data2);
mySerial.print(data2, BYTE);
digitalWrite(ledPin, LOW);
}
To be continued in next post....
[Continuation of my prior post]
That seems to work well enough, but one thing I'd really like to improve is the "feel" of the beat and the ability to plug in more complicated sequences. As currently set up, each beat is locked in a static "grid" and I can't easily add additional subdivisions (such as 32nd notes or triplets), or play notes longer than a 16th. Also, the timing might be a bit off since calculations happen between each delay. I can't tell.
So, for my next step I'd like to play a MIDI file, or perhaps a sanitized, simplified version thereof, using a timer instead of delays. I've seen examples of how to accomplish a single task using a timer, but I get confused when trying to apply to a long list of events. In pseudo-code, I'd like to:
Is that a sensible way to set it up? How could I optimize it better to allow more cycles for reading and interpreting input?
I've given a first shot at coding this, but I'm getting errors relating to pointers (which I'm trying to learn about) in the loop() section where I look up the note in the array (2nd field) based on the tick in the array (1st field). Should I be setting this up differently, or would it be a simple syntax tweak to fix this?
#include <NewSoftSerial.h>
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 indicator
int instrument = 0;
int scale_major[] = {0, 2, 4, 5, 7, 9, 11}; //one octave of major scale
int scale_minpent[] = {0, 2, 3, 5, 6, 7, 10}; //minor pentatonic scale
int scale_consonant[] = {0, 2, 4, 7, 9, 12, 14}; //major pentatonic scale plus octave and 9th (to be same array length as others)
int drum_motown[100][3] = //Tick (out of 384 per bar), note, velocity
{ //This is an attempt to adapt data from an actual MIDI file, with
{ 0,54,94 }, //matching 0-velocity lines in place of noteOff messages
{ 0,48,97 },
{ 8,54,0 },
{ 48,54,75 },
{ 51,48,0 },
{ 54,54,0 },
{ 96,50,106 },
{ 96,54,96 },
{ 103,54,0 },
{ 127,50,0 },
{ 144,54,73 },
{ 153,54,0 },
{ 171,50,92 },
{ 177,50,0 },
{ 192,54,82 },
{ 201,54,0 },
{ 219,48,85 },
{ 240,54,84 },
{ 240,48,0 },
{ 246,54,0 },
{ 267,48,86 },
{ 273,48,0 },
{ 288,54,101 },
{ 288,50,103 },
{ 296,54,0 },
{ 318,50,0 },
{ 336,54,77 },
{ 344,54,0 },
{ 363,50,70 },
{ 368,50,0 }
};
int drumSpot = 0;
int drumSpotTime = 0;
long curTime = 0;
int timeclock96 = 0; //96 ticks per beat, based on 4 subdivs per beat and 24 ticks per subdiv (not 240 like the source midi file)
void setup() {
Serial.begin(57600);
//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);
talkMIDI(0xB0, 0x07, 30); //0xB0 is channel message for channel 1 (0), set channel volume to 30
talkMIDI(0xB0, 0, 0x00); //Bank select GM1
talkMIDI(0xB9, 0x07, 50); //0xB0 is channel message for channel 10 (9), set channel volume to 50
talkMIDI(0xB9, 0, 0x78); //Bank select drums
curTime = millis();
}
void loop() {
timeclock96 = (millis() - curTime)/96;
Serial.println(timeclock96);
for (int j = drumSpot; j<100; j++) {
drumSpotTime = (int)drum_motown[drumSpot,0];
if (drumSpotTime < timeclock96) {
noteOn(0, (byte)10, drum_motown[drumSpot,1], drum_motown[drumSpot,2]); //ERROR HERE: invalid conversion from int* to byte
}
if (timeclock96 >= 96) {
curTime = millis();
}
// playNoodling(0, random(48,59), scale_consonant, 180, 0);
}
void playNoodling(byte channel, int key, int scale[], float tempo, int instrument) {
Serial.print(" Instrument: ");
Serial.println(instrument, DEC);
talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1 data byte command
talkMIDI(0xCA, 30, 0); //Set instrument number. 0xC0 is a 1 data byte command
for (int i = 0; i < 16; i++) {
int note = key + scale[random(0, 6)];
noteOn(1, channel, note, 80);
noteOn(0, 10, drum_pattern1[i], 50);
//1 minute 60 seconds 1000 ms
//--------- x --------- x --------
//120 Beats 1 minute 1 second
delay(60000/tempo);
noteOff(1, channel, note, 0);
noteOff(0, 10, drum_pattern1[i], 0);
}
}
void allOff(byte channel) {
talkMIDI ( (0xB0 | channel), 123, 0);
}
//Send a MIDI note-on message. Like pressing a piano key
//channel ranges from 0-15
void noteOn(boolean instr, 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(boolean instr, 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);
// Serial.write(cmd);
// Serial.write(data1);
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)
// Serial.write(data2);
mySerial.print(data2, BYTE);
digitalWrite(ledPin, LOW);
}
Many thanks in advance to anyone who can provide a suggestion as to how to improve this code! My apologies that it's so scrappy!
try this one.it worked for me
Here is the link for what I have made by reading MIDI files and playig drum:
Full Video: Imagine Dragons - Believer - Arduino Drum - YouTube
Code and Everything: Imagine Dragons – Believer – Arduino – TinAndJar