We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
Page Index Toggle Pages: 1
Loading midi files? (Read 1417 times)
Loading midi files?
Nov 18th, 2008, 12:27am
 
Is this possible at all? I'm essentially making a Guitar Hero clone, and using midi to store the fret data seems like the most logical approach... but can it be done?

Cheers
Re: Loading midi files?
Reply #1 - Nov 18th, 2008, 1:04am
 
So I did a little bit of Java digging, and got together what I thought should be loading a midi file:

import java.io.File;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;

MidiSystem midiSystem;

void setup(){
 size(128*5,128*5);
 smooth();
 background(0);
 
 File midiFile = new File("MidiTest.mid");
 
 println(midiFile);

 Sequence midiSequence = midiSystem.getSequence(midiFile);

}

The file is just a simple 1 bar midi file with one note made in Ableton Live. When I run it, though, I get an "Unhandled exception type InvalidMidiDataException". From the java docs, apparently this means:

This operation can only succeed for files of a type which can be parsed by an installed file reader. It may fail with an InvalidMidiDataException even for valid files if no compatible file reader is installed. It will also fail with an InvalidMidiDataException if a compatible file reader is installed, but encounters errors while constructing the Sequence  object from the file data.

So whats going wrong, and how do I fix this?

I'm on OSX 10.5
Re: Loading midi files?
Reply #2 - Nov 18th, 2008, 2:45pm
 
Heres a function I created last night which will load a midi file and return back an ArrayList of notes + their times.




ArrayList loadMidi(String fileName)
{
 
 String sketchPath = this.sketchPath;
 println(sketchPath);
 
 File midiFile = new File(sketchPath + "/" + fileName);
 
 println(midiFile.getAbsolutePath());
 
 if(!midiFile.exists() || midiFile.isDirectory() || !midiFile.canRead())
 {
   println("Error reading file");
 }
 
 Sequence midiSequence = null;

 try
 {
   midiSequence = midiSystem.getSequence(midiFile);
 }
 catch (Exception e)
 {
   e.printStackTrace();
 }
 
 if (midiSequence == null)
 {
   return null;
 }
 
 try
 {
   midiSequencer = midiSystem.getSequencer();
 }
 catch (Exception e)
 {
   println(e);
 }
 
 try
 {
   midiSequencer.setSequence(midiSequence);
 }
 catch (Exception e)
 {
   e.printStackTrace();
 }
 
 Track[] midiTracks = midiSequence.getTracks();
 
 //println("num tracks: " + midiTracks.length);
 
 Track midiTrack = midiTracks[0];
 
 int iNumEvents = midiTrack.size();
 
 //println("num events: " + iNumEvents);
 
 ArrayList myNotes = new ArrayList();
 
 for (int i=0; i<iNumEvents; i++)
 {
   MidiEvent event = midiTrack.get(i);
   
   MidiMessage message = event.getMessage();
   
   if (message.getLength()-1 == 2) //message length - staus byte = 2 (short message)
   {
     
     int iMessage = (int)(message.getMessage()[0] & 0xFF);
     
     if (iMessage == ShortMessage.NOTE_ON)
     {        
       int iFullNote = (int)(message.getMessage()[1] & 0xFF);
       
       int iNote = iFullNote % 12;
       int iOctave = floor(iFullNote/12) - 2;
       
       float fBPS = 132.0 / 60.0;
       float fSPB = 1.0 / fBPS;
       
       float fTime = event.getTick() * fSPB / 96;
       
       //println("Note On: " + Notes[iNote] + "-" + iOctave + " @" + fTime);
       
       Note n = new Note();
       n.m_sNote = Notes[iNote];
       n.m_fTime = fTime;
       myNotes.add(n);
       
       //384 ticks per bar?
     }
   }
 }
 
 return myNotes;
 
}
Re: Loading midi files?
Reply #3 - Nov 18th, 2008, 6:04pm
 
nice work,

but you miss one thing, the duration of the note Wink.
Re: Loading midi files?
Reply #4 - Nov 19th, 2008, 3:43pm
 
didn't need it so i left it out Wink

maybe it would be nice to have, though.
Re: Loading midi files?
Reply #5 - Nov 21st, 2008, 6:14pm
 
Hey that is exactly what I was looking for. But I tried to use your function but it doesn't work :( it doesn't find a midiSequencer variable, and it doesn't recognize the "Note" and the shortMessage :/
Re: Loading midi files?
Reply #6 - Nov 22nd, 2008, 8:59pm
 
oops my appologies... heres the correct stuff

Code:


import javax.sound.midi.Sequencer;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.InvalidMidiDataException;
import java.io.IOException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Track;
import javax.sound.midi.ShortMessage;

MidiSystem midiSystem;
Sequencer midiSequencer;

String[] Notes = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};

class Note
{
float m_fTime;
String m_sNote;
}



class Song
{

Song(String sName)
{
m_sName = sName;
}

String m_sName = "";
ArrayList m_Notes = new ArrayList();
}



int g_iTicksPerBeat = 96;

ArrayList loadMidi(String fileName, float fBPM)
{

String sketchPath = this.sketchPath;
println(sketchPath);

File midiFile = new File(sketchPath + "/" + fileName);

println(midiFile.getAbsolutePath());

if(!midiFile.exists() || midiFile.isDirectory() || !midiFile.canRead())
{
println("Error reading file");
}

Sequence midiSequence = null;

try
{
midiSequence = midiSystem.getSequence(midiFile);
}
catch (Exception e)
{
e.printStackTrace();
}

if (midiSequence == null)
{
return null;
}


Track[] midiTracks = midiSequence.getTracks();
Track midiTrack = midiTracks[0];

int iNumEvents = midiTrack.size();

ArrayList myNotes = new ArrayList();

for (int i=0; i<iNumEvents; i++)
{
MidiEvent event = midiTrack.get(i);

MidiMessage message = event.getMessage();

if (message.getLength()-1 == 2) //message length - staus byte = 2 (short message)
{

int iMessage = (int)(message.getMessage()[0] & 0xFF);

if (iMessage == ShortMessage.NOTE_ON)
{
int iFullNote = (int)(message.getMessage()[1] & 0xFF);

int iNote = iFullNote % 12;
int iOctave = floor(iFullNote/12) - 2;

float fBPS = fBPM / 60.0;
float fSPB = 1.0 / fBPS;

float fTime = event.getTick() * fSPB / g_iTicksPerBeat;

//println("Note On: " + Notes[iNote] + "-" + iOctave + " @" + fTime + "[" + event.getTick() + "]");

Note n = new Note();
n.m_sNote = Notes[iNote];
n.m_fTime = fTime;
myNotes.add(n);

//384 ticks per bar?
}
}
}

return myNotes;

}



that *should* work, let me know if it doesn't.
Re: Loading midi files?
Reply #7 - Nov 22nd, 2008, 11:37pm
 
Oh thanks for posting that !
I just tried, and it doesn't show error messages anymore :)
But the arrayList it returns is empty :(

I tried with this file, misery.mid ("http://rock.mididb.com/beatles/")
and it returns me nothing but "[]"
I took a look and saw that the iMessage variable is always set to 255 and never 144 (ShortMessage.NOTE_ON) so it doesn't happen anything
for this .mid, the Track length is 12 and size is 7.
So I'm a bit lost. I think I have to understand really what is a track and all that...
But thank you for your code, and if have any idea.. ;)
Re: Loading midi files?
Reply #8 - Nov 22nd, 2008, 11:49pm
 
OK I don't understand why but I seems to work now !

I just changed this :
Track midiTrack = midiTracks[0];

to

Track midiTrack = midiTracks[1];

and delete :

if (message.getLength()-1 == 2)
//message length - staus byte = 2 (short message)
{
}

I don't understand why you wrote this condition and what is a staus byte.
But now it returns me data like that :

...
Note On: E-3 @32.4[5184]
Note On: B-3 @33.000004[5280]
Note On: G#-3 @33.000004[5280]
Note On: E-3 @33.000004[5280]
Note On: E-4 @33.600002[5376]
Note On: B-3 @33.600002[5376]
...

So it looks okay (even if I'm not sure ;)
thanks again.
Re: Loading midi files?
Reply #9 - Nov 22nd, 2008, 11:55pm
 
the condition is to check if its a short midi message (ie one with only three bytes). i was working from some midi specification i found online, which basically said a short midi message has one status byte and two message bytes.

that statement was just ensuring it was definitely a short message that was getting looked at.

is it needed? im not sure. im no midi expert, and i was really just aiming to get some code together that worked without any intentions of sharing it (hence the messyness!)

i'm suprised that midi file loading hasnt been included in a library. weird.
Re: Loading midi files?
Reply #10 - Nov 23rd, 2008, 12:46am
 
yes it is !
Your code will be very useful, thank you very much :)
Page Index Toggle Pages: 1