Created
June 22, 2012 09:52
-
-
Save sport4minus/2971754 to your computer and use it in GitHub Desktop.
Convenient classes for loading and analyzing midi files in Processing / java, using the Sequence Object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MidiLoader { | |
/** | |
*loads a midi file from disk and stores all notes in a nested Array List, using the Helper class "Note" | |
* needs some cleanup though | |
*/ | |
ArrayList<ArrayList<Note>> tracks; | |
long maxTicks = 0; | |
final boolean DO_PRINT = false; | |
MidiLoader(String fileName) { | |
//Notes are stored in this nested array list to mirror the track-note structure (depending on type of midi file) | |
tracks = new ArrayList<ArrayList<Note>>(); | |
Track[] trx; | |
try { | |
File myMidiFile = new File(dataPath(fileName)); | |
Sequence mySeq = MidiSystem.getSequence(myMidiFile); | |
trx = mySeq.getTracks(); | |
for (int i = 0; i < trx.length; i++) { | |
ArrayList<Note> trackAsList = new ArrayList<Note>(); | |
tracks.add(trackAsList); | |
Track t = trx[i]; | |
if (DO_PRINT) { | |
println("track "); | |
println("length:"+ t.ticks()); | |
println("num events:" + t.size()); | |
} | |
int counter = 0; | |
//iterate over the vector, and remove each handled event. | |
while (t.size () > 0 && counter < t.size()) { | |
counter ++; | |
if (t.get(0).getMessage() instanceof ShortMessage) { | |
ShortMessage s = (ShortMessage)(t.get(0).getMessage()); | |
//find note on events | |
if (s.getCommand() == ShortMessage.NOTE_ON) { | |
if (DO_PRINT)println(s.getCommand() + " " + s.getChannel() +" " + s.getData1() + " " + s.getData2()); | |
//store all the values temporarily in order to find the associated note off event | |
long startTime = t.get(0).getTick(); | |
long endTime = 0; | |
int ch = s.getChannel(); | |
int pitch = s.getData1(); | |
int vel = s.getData2(); | |
//if the first note has zero velocity (== noteOff), remove it | |
if (vel == 0) { | |
t.remove(t.get(0)); | |
} | |
else { | |
//start to look for the associated note off | |
for (int j = 0; j < t.size(); j++) { | |
if (t.get(j).getMessage() instanceof ShortMessage) { | |
ShortMessage s2 = (ShortMessage)(t.get(j).getMessage()); | |
//two types to send a note off... either as a clean command or as note on with 0 velocity | |
if ((s2.getCommand() == ShortMessage.NOTE_OFF) || s2.getCommand() == ShortMessage.NOTE_ON) { | |
//compare to stored values, sending a note off with same channel and pitch means to stop the note | |
if (s2.getChannel() == ch && s2.getData1() == pitch && s2.getData2() == 0) { | |
//calculate note duration | |
endTime = t.get(j).getTick(); | |
//extend maxticks, so we know when the last midi event happened (sometimes tracks are much longer than the last note | |
if (endTime > maxTicks)maxTicks = endTime; | |
//create a new "Note" instance, store it | |
Note n = new Note(startTime, endTime-startTime, ch, vel, pitch); | |
trackAsList.add(n); | |
t.remove(t.get(0)); | |
break; | |
} | |
} | |
} | |
} | |
} | |
//remove event when done | |
t.remove(t.get(0)); | |
} | |
else { | |
//remove events which are shortmessages but not note on (e.g. control change) | |
t.remove(t.get(0)); | |
} | |
} | |
else { | |
//remove events which are not of type short message | |
t.remove(t.get(0)); | |
} | |
} | |
} | |
} | |
catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
ArrayList<Note> trackAsArrayList(int i) { | |
return tracks.get(i); | |
// return null; | |
} | |
int numTracks() { | |
return tracks.size(); | |
} | |
} | |
/** | |
*Helper Class Note, stores start time, end time, channel, pitch and duration | |
*/ | |
class Note { | |
long start; | |
long duration; | |
int channel; | |
int velocity; | |
int pitch; | |
Note(long theStart, long theDuration, int theChannel, int theVelocity, int thePitch) { | |
start = theStart; | |
channel = theChannel; | |
pitch = thePitch; | |
velocity = theVelocity; | |
duration = theDuration; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment