annotate MidiPlayer.java @ 0:4031cbb02f08

Initial import. Ignore-this: 87317e384f22bde48db996355191fa5f
author Marcus Pearce <m.pearce@gold.ac.uk>
date Tue, 18 May 2010 11:37:10 +0100
parents
children 93ed757b9871
rev   line source
m@0 1 /*=============================================================================
m@0 2 * File: MidiPlayer.java
m@0 3 * Author: Marcus Pearce <m.pearce@gold.ac.uk>
m@0 4 * Created: <2007-02-14 12:13:56 marcusp>
m@0 5 * Time-stamp: <2008-10-20 16:52:05 marcusp>
m@0 6 *=============================================================================
m@0 7 */
m@0 8
m@0 9 /*
m@0 10 * Based on:
m@0 11 * http://www.jsresources.org/examples/SimpleMidiPlayer.html
m@0 12 * http://www.jsresources.org/examples/DumpSequence.html
m@0 13 */
m@0 14
m@0 15 import java.io.File;
m@0 16 import java.io.IOException;
m@0 17 import java.util.ArrayList;
m@0 18
m@0 19 import javax.sound.midi.MidiSystem;
m@0 20 import javax.sound.midi.MidiDevice;
m@0 21 import javax.sound.midi.InvalidMidiDataException;
m@0 22 import javax.sound.midi.MidiUnavailableException;
m@0 23 import javax.sound.midi.MetaEventListener;
m@0 24 import javax.sound.midi.Sequence;
m@0 25 import javax.sound.midi.Sequencer;
m@0 26 import javax.sound.midi.Synthesizer;
m@0 27 import javax.sound.midi.MidiChannel;
m@0 28 import javax.sound.midi.Receiver;
m@0 29 import javax.sound.midi.Transmitter;
m@0 30 import javax.sound.midi.Track;
m@0 31 import javax.sound.midi.MidiEvent;
m@0 32 import javax.sound.midi.MidiMessage;
m@0 33 import javax.sound.midi.ShortMessage;
m@0 34 import javax.sound.midi.MetaMessage;
m@0 35 import javax.sound.midi.SysexMessage;
m@0 36 import javax.sound.midi.MetaMessage;
m@0 37
m@0 38 public class MidiPlayer {
m@0 39
m@0 40 /* variables */
m@0 41 private Sequencer sequencer = null;
m@0 42 private Synthesizer synthesizer = null;
m@0 43 private Sequence sequence = null;
m@0 44 private ArrayList onsets, offsets, pitches = null;
m@0 45 private int midiDevice = 0; /* 4 for usb midi device */
m@0 46
m@0 47 /* accessors */
m@0 48 public Sequencer getSequencer() { return sequencer; }
m@0 49
m@0 50 /* Constructor */
m@0 51 public MidiPlayer(String path) {
m@0 52 File midiFile = new File(path);
m@0 53
m@0 54 // Get sequence
m@0 55 try { sequence = MidiSystem.getSequence(midiFile); }
m@0 56 catch (InvalidMidiDataException e) {
m@0 57 e.printStackTrace();
m@0 58 System.exit(1);
m@0 59 }
m@0 60 catch (IOException e) {
m@0 61 e.printStackTrace();
m@0 62 System.exit(1);
m@0 63 }
m@0 64 // Get sequencer
m@0 65 try { sequencer = MidiSystem.getSequencer(); }
m@0 66 catch (MidiUnavailableException e) {
m@0 67 e.printStackTrace();
m@0 68 System.exit(1);
m@0 69 }
m@0 70 //sequencer.setTempoInBPM(bpm);
m@0 71 // Workaround bug in JDK
m@0 72 // sequencer.addMetaEventListener(new MetaEventListener() {
m@0 73 // public void meta(MetaMessage event) {
m@0 74 // if (event.getType() == 47) {
m@0 75 // sequencer.close();
m@0 76 // if (synthesizer != null) {
m@0 77 // synthesizer.close();
m@0 78 // }
m@0 79 // }
m@0 80 // }
m@0 81 // });
m@0 82 // Open sequencer
m@0 83 try { sequencer.open(); }
m@0 84 catch (MidiUnavailableException e) {
m@0 85 e.printStackTrace();
m@0 86 System.exit(1);
m@0 87 }
m@0 88 // Assign sequence to sequencer
m@0 89 try { sequencer.setSequence(sequence); }
m@0 90 catch (InvalidMidiDataException e) {
m@0 91 e.printStackTrace();
m@0 92 System.exit(1);
m@0 93 }
m@0 94 // Set up MIDI output for sequence
m@0 95 try {
m@0 96 MidiDevice.Info msinfo[] = MidiSystem.getMidiDeviceInfo();
m@0 97 for(int i = 0; i < msinfo.length; i++) {
m@0 98 MidiDevice.Info m = msinfo[i];
m@0 99 // System.out.println("Name: " + m.getName() +
m@0 100 // "; Vendor: " + m.getVendor() +
m@0 101 // "; Version: " + m.getVersion());
m@0 102 }
m@0 103 // synthesizer = MidiSystem.getSynthesizer();
m@0 104 MidiDevice synth = MidiSystem.getMidiDevice(msinfo[midiDevice]);
m@0 105
m@0 106 // Change the patch
m@0 107 // MidiChannel channels[] = synthesizer.getChannels();
m@0 108 // for (int i = 0; i < channels.length; i++)
m@0 109 // channels[i].programChange(65);
m@0 110
m@0 111 synth.open();
m@0 112 Receiver synthReceiver = synth.getReceiver();
m@0 113 Transmitter seqTransmitter = sequencer.getTransmitter();
m@0 114 seqTransmitter.setReceiver(synthReceiver);
m@0 115
m@0 116 }
m@0 117 catch (MidiUnavailableException e) {
m@0 118 e.printStackTrace();
m@0 119 }
m@0 120
m@0 121 // compute data from the MIDI file
m@0 122 onsets = computeOnsets();
m@0 123 offsets = computeOffsets();
m@0 124 pitches = computePitches();
m@0 125
m@0 126 //String divisionType;
m@0 127 //if (sequence.getDivisionType() == sequence.PPQ)
m@0 128 // divisionType = "ppq";
m@0 129 //else
m@0 130 // divisionType = "smpte";
m@0 131 //System.out.println("division type = " + divisionType +
m@0 132 // "; resolution = " + sequence.getResolution());
m@0 133 }
m@0 134
m@0 135 /* number of microseconds per MIDI tick */
m@0 136 private double microsecondsPerTick() {
m@0 137 double seqTickLength = (float)sequence.getTickLength();
m@0 138 double seqMicrosecondLength = (float)sequence.getMicrosecondLength();
m@0 139 double microsecondsPerTick = seqMicrosecondLength / seqTickLength;
m@0 140 //System.out.println("seqTickLength = " + seqTickLength);
m@0 141 //System.out.println("seqMicrosecondLength = " + seqMicrosecondLength);
m@0 142 //System.out.println("microsecondsPerTick = " + microsecondsPerTick);
m@0 143 return microsecondsPerTick;
m@0 144 }
m@0 145
m@0 146 private long ticksToMicroseconds(long tick) {
m@0 147 double microsecondsPerTick = microsecondsPerTick();
m@0 148 double seconds = (double)tick * microsecondsPerTick;
m@0 149
m@0 150 return (long)(10 * Math.floor(seconds * 0.1));
m@0 151 }
m@0 152
m@0 153 /* compute a list of note onset times (microseconds) */
m@0 154 private ArrayList computeOnsets() {
m@0 155 ArrayList ons = new ArrayList();
m@0 156 Track[] tracks = sequence.getTracks();
m@0 157
m@0 158 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
m@0 159 Track track = tracks[nTrack];
m@0 160 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
m@0 161 MidiEvent event = track.get(nEvent);
m@0 162 MidiMessage message = event.getMessage();
m@0 163 if (message instanceof ShortMessage &&
m@0 164 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_ON) {
m@0 165 // System.out.println("onset in ticks = " + event.getTick()+
m@0 166 // "; onset in microseconds = " +
m@0 167 // ticksToMicroseconds(event.getTick()));
m@0 168 ons.add(ticksToMicroseconds(event.getTick()));
m@0 169 }
m@0 170 }
m@0 171 }
m@0 172 return ons;
m@0 173 }
m@0 174
m@0 175 /* compute a list of note offset times (microseconds) */
m@0 176 private ArrayList computeOffsets() {
m@0 177 ArrayList offs = new ArrayList();
m@0 178 Track[] tracks = sequence.getTracks();
m@0 179
m@0 180 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
m@0 181 Track track = tracks[nTrack];
m@0 182 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
m@0 183 MidiEvent event = track.get(nEvent);
m@0 184 MidiMessage message = event.getMessage();
m@0 185 if (message instanceof ShortMessage &&
m@0 186 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_OFF) {
m@0 187 //System.out.println("offset in ticks = " + event.getTick()+
m@0 188 // "; microsecondsPerTick = " + microsecondsPerTick +
m@0 189 // "; offset in microseconds = " +
m@0 190 // (float)event.getTick() * microsecondsPerTick);
m@0 191 offs.add(ticksToMicroseconds(event.getTick()));
m@0 192 }
m@0 193 }
m@0 194 }
m@0 195 return offs;
m@0 196 }
m@0 197
m@0 198 /* compute a list of note pitches */
m@0 199 private ArrayList computePitches() {
m@0 200 ArrayList pit = new ArrayList();
m@0 201 Track[] tracks = sequence.getTracks();
m@0 202
m@0 203 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
m@0 204 Track track = tracks[nTrack];
m@0 205 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
m@0 206 MidiEvent event = track.get(nEvent);
m@0 207 MidiMessage message = event.getMessage();
m@0 208 if (message instanceof ShortMessage &&
m@0 209 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_ON)
m@0 210 pit.add(((ShortMessage)message).getData1());
m@0 211 }
m@0 212 }
m@0 213 return pit;
m@0 214 }
m@0 215
m@0 216 /* return a list of note onset times (milliseconds) */
m@0 217 public ArrayList getOnsets() { return onsets; }
m@0 218
m@0 219 /* return a list of note offset times (milliseconds) */
m@0 220 public ArrayList getOffsets() { return offsets; }
m@0 221
m@0 222 /* return a list of note pitches */
m@0 223 public ArrayList getPitches() { return pitches; }
m@0 224
m@0 225 /* return a list of note durations (microseconds) */
m@0 226 public ArrayList getDurations() {
m@0 227 Object[] ons = onsets.toArray();
m@0 228 Object[] offs = offsets.toArray();
m@0 229
m@0 230 ArrayList durations = new ArrayList();
m@0 231
m@0 232 for(int i = 0; i < ons.length; i++) {
m@0 233 durations.add(((Long)offs[i]).longValue() -
m@0 234 ((Long)ons[i]).longValue());
m@0 235 }
m@0 236 return durations;
m@0 237 }
m@0 238
m@0 239 /* return a list of inter-onset intervals (microseconds) */
m@0 240 public ArrayList getInterOnsetIntervals() {
m@0 241 Object[] ons = onsets.toArray();
m@0 242
m@0 243 ArrayList iois = new ArrayList();
m@0 244 long firstIOI = 0;
m@0 245 iois.add(firstIOI); // IOI of first note is zero
m@0 246
m@0 247 for(int i = 1; i < ons.length; i++) {
m@0 248 iois.add(((Long)ons[i]).longValue() -
m@0 249 ((Long)ons[i-1]).longValue());
m@0 250 }
m@0 251 return iois;
m@0 252 }
m@0 253
m@0 254 /* return the length of a rest preceding a note */
m@0 255 public ArrayList getDeltaST() {
m@0 256 Object[] durs = getDurations().toArray();
m@0 257 Object[] iois = getInterOnsetIntervals().toArray();
m@0 258
m@0 259 ArrayList deltaST = new ArrayList();
m@0 260 long firstDeltaST = 0;
m@0 261 deltaST.add(firstDeltaST); // deltaST of first note is zero
m@0 262
m@0 263 for(int i = 1; i < durs.length; i++) {
m@0 264 deltaST.add(((Long)durs[i-1]).longValue() -
m@0 265 ((Long)iois[i]).longValue());
m@0 266 }
m@0 267 return deltaST;
m@0 268 }
m@0 269
m@0 270 /* return the tatum of the midi file */
m@0 271 public long getTatum() {
m@0 272 Object[] durs = getDurations().toArray();
m@0 273 Object[] rests = getDeltaST().toArray();
m@0 274 long tatum = -1;
m@0 275
m@0 276 for(int i = 0; i < durs.length; i++) {
m@0 277 long dur = ((Long)durs[i]).longValue();
m@0 278 long rest = ((Long)rests[i]).longValue();
m@0 279 long min = dur;
m@0 280 if (rest != 0)
m@0 281 min = Math.min(dur, rest);
m@0 282
m@0 283 if (tatum < 0)
m@0 284 tatum = dur;
m@0 285 else if (min < tatum)
m@0 286 tatum = min;
m@0 287 }
m@0 288 return tatum;
m@0 289 }
m@0 290
m@0 291 /* return length of sequence in microseconds */
m@0 292 public long getLength() {
m@0 293 return sequence.getMicrosecondLength();
m@0 294 }
m@0 295
m@0 296 /* play the midi file */
m@0 297 public void play() {
m@0 298 sequencer.start();
m@0 299 }
m@0 300
m@0 301 public void stop() {
m@0 302 sequencer.close();
m@0 303 }
m@0 304 }