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>
|
marcus@16
|
5 * Time-stamp: <2011-11-15 16:52:06 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;
|
JShulver@22
|
37 import java.util.Arrays;
|
jeremy@24
|
38 import java.util.Iterator;
|
jeremy@24
|
39
|
jeremy@24
|
40
|
m@0
|
41 public class MidiPlayer {
|
m@0
|
42
|
m@0
|
43 /* variables */
|
m@0
|
44 private Sequencer sequencer = null;
|
m@0
|
45 private Synthesizer synthesizer = null;
|
m@0
|
46 private Sequence sequence = null;
|
jeremy@24
|
47 private ArrayList<Long> onsets, offsets = null;
|
CBussey@39
|
48 private ArrayList<Integer> pitches, velocities = null;
|
CBussey@39
|
49 private File midiFile;
|
CBussey@39
|
50 private boolean defaultMD = false;
|
CBussey@39
|
51 private int midiDevice;
|
jeremy@24
|
52 private boolean debug;
|
m@0
|
53
|
m@0
|
54 /* accessors */
|
CBussey@39
|
55 public Sequencer getSequencer() { return sequencer; }
|
CBussey@39
|
56 public boolean usingDefault() { return defaultMD; }
|
m@0
|
57
|
CBussey@39
|
58 /* Constructors */
|
CBussey@39
|
59 public MidiPlayer(String path, int deviceNumber, boolean d) {
|
CBussey@39
|
60 if(deviceNumber == -1) {
|
CBussey@39
|
61 defaultMD = true;
|
CBussey@39
|
62 midiDevice = 0;
|
CBussey@39
|
63 }
|
CBussey@39
|
64 else{
|
CBussey@39
|
65 midiDevice = deviceNumber;
|
CBussey@39
|
66 }
|
CBussey@39
|
67 midiFile = new File(path);
|
CBussey@39
|
68 debug = d;
|
CBussey@39
|
69 setup();
|
CBussey@39
|
70 }
|
CBussey@39
|
71
|
CBussey@39
|
72 private void setup(){
|
CBussey@39
|
73 // Get sequence
|
m@0
|
74 try { sequence = MidiSystem.getSequence(midiFile); }
|
m@0
|
75 catch (InvalidMidiDataException e) {
|
m@0
|
76 e.printStackTrace();
|
m@0
|
77 System.exit(1);
|
m@0
|
78 }
|
m@0
|
79 catch (IOException e) {
|
m@0
|
80 e.printStackTrace();
|
m@0
|
81 System.exit(1);
|
m@0
|
82 }
|
m@0
|
83 //sequencer.setTempoInBPM(bpm);
|
m@0
|
84 // Workaround bug in JDK
|
m@0
|
85 // sequencer.addMetaEventListener(new MetaEventListener() {
|
m@0
|
86 // public void meta(MetaMessage event) {
|
m@0
|
87 // if (event.getType() == 47) {
|
m@0
|
88 // sequencer.close();
|
m@0
|
89 // if (synthesizer != null) {
|
m@0
|
90 // synthesizer.close();
|
m@0
|
91 // }
|
m@0
|
92 // }
|
m@0
|
93 // }
|
m@0
|
94 // });
|
CBussey@39
|
95 // Set up MIDI output for sequence
|
m@0
|
96 try {
|
m@0
|
97 MidiDevice.Info msinfo[] = MidiSystem.getMidiDeviceInfo();
|
m@0
|
98 for(int i = 0; i < msinfo.length; i++) {
|
CBussey@39
|
99 MidiDevice.Info m = msinfo[i];
|
CBussey@39
|
100 System.out.println("Name: " + m.getName() +
|
CBussey@39
|
101 "; Vendor: " + m.getVendor() +
|
CBussey@39
|
102 "; Version: " + m.getVersion());
|
m@0
|
103 }
|
CBussey@39
|
104 MidiDevice synth = MidiSystem.getMidiDevice(msinfo[midiDevice]);
|
CBussey@39
|
105 synth.open();
|
CBussey@39
|
106 // Get sequencer
|
CBussey@39
|
107 try { sequencer = MidiSystem.getSequencer(defaultMD); }
|
CBussey@39
|
108 catch (MidiUnavailableException e) {
|
CBussey@39
|
109 e.printStackTrace();
|
CBussey@39
|
110 System.exit(1);
|
CBussey@39
|
111 }
|
m@0
|
112 // synthesizer = MidiSystem.getSynthesizer();
|
CBussey@39
|
113
|
CBussey@39
|
114 try { sequencer.open(); }////
|
CBussey@39
|
115 catch (MidiUnavailableException e) {
|
CBussey@39
|
116 e.printStackTrace();
|
CBussey@39
|
117 System.exit(1);
|
CBussey@39
|
118 }
|
CBussey@39
|
119 // Assign sequence to sequencer
|
CBussey@39
|
120 try { sequencer.setSequence(sequence); }
|
CBussey@39
|
121 catch (InvalidMidiDataException e) {
|
CBussey@39
|
122 e.printStackTrace();
|
CBussey@39
|
123 System.exit(1);
|
CBussey@39
|
124 }////
|
m@0
|
125
|
m@0
|
126 // Change the patch
|
m@0
|
127 // MidiChannel channels[] = synthesizer.getChannels();
|
m@0
|
128 // for (int i = 0; i < channels.length; i++)
|
m@0
|
129 // channels[i].programChange(65);
|
CBussey@39
|
130
|
m@0
|
131 Receiver synthReceiver = synth.getReceiver();
|
m@0
|
132 Transmitter seqTransmitter = sequencer.getTransmitter();
|
m@0
|
133 seqTransmitter.setReceiver(synthReceiver);
|
m@0
|
134
|
m@0
|
135 }
|
m@0
|
136 catch (MidiUnavailableException e) {
|
m@0
|
137 e.printStackTrace();
|
m@0
|
138 }
|
m@0
|
139
|
m@0
|
140 // compute data from the MIDI file
|
jeremy@24
|
141
|
jeremy@24
|
142 /*
|
m@0
|
143 onsets = computeOnsets();
|
m@0
|
144 offsets = computeOffsets();
|
m@0
|
145 pitches = computePitches();
|
jeremy@24
|
146 */
|
jeremy@24
|
147 registerEvents();
|
m@0
|
148
|
jeremy@24
|
149 if (debug) {
|
jeremy@24
|
150 String divisionType;
|
jeremy@24
|
151 if (sequence.getDivisionType() == sequence.PPQ)
|
jeremy@24
|
152 divisionType = "ppq";
|
jeremy@24
|
153 else
|
jeremy@24
|
154 divisionType = "smpte";
|
jeremy@24
|
155 System.out.println("division type = " + divisionType +
|
jeremy@24
|
156 "; resolution = " + sequence.getResolution());
|
jeremy@24
|
157 }
|
m@0
|
158 }
|
m@0
|
159
|
m@0
|
160 /* number of microseconds per MIDI tick */
|
m@0
|
161 private double microsecondsPerTick() {
|
m@0
|
162 double seqTickLength = (float)sequence.getTickLength();
|
m@0
|
163 double seqMicrosecondLength = (float)sequence.getMicrosecondLength();
|
m@0
|
164 double microsecondsPerTick = seqMicrosecondLength / seqTickLength;
|
m@0
|
165 //System.out.println("seqTickLength = " + seqTickLength);
|
m@0
|
166 //System.out.println("seqMicrosecondLength = " + seqMicrosecondLength);
|
m@0
|
167 //System.out.println("microsecondsPerTick = " + microsecondsPerTick);
|
m@0
|
168 return microsecondsPerTick;
|
m@0
|
169 }
|
m@0
|
170
|
m@0
|
171 private long ticksToMicroseconds(long tick) {
|
m@0
|
172 double microsecondsPerTick = microsecondsPerTick();
|
m@0
|
173 double seconds = (double)tick * microsecondsPerTick;
|
m@0
|
174
|
m@0
|
175 return (long)(10 * Math.floor(seconds * 0.1));
|
m@0
|
176 }
|
m@0
|
177
|
m@0
|
178 /* compute a list of note onset times (microseconds) */
|
m@0
|
179 private ArrayList computeOnsets() {
|
m@0
|
180 ArrayList ons = new ArrayList();
|
m@0
|
181 Track[] tracks = sequence.getTracks();
|
m@0
|
182
|
m@0
|
183 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
|
m@0
|
184 Track track = tracks[nTrack];
|
m@0
|
185 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
|
m@0
|
186 MidiEvent event = track.get(nEvent);
|
m@0
|
187 MidiMessage message = event.getMessage();
|
m@0
|
188 if (message instanceof ShortMessage &&
|
m@0
|
189 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_ON) {
|
m@0
|
190 // System.out.println("onset in ticks = " + event.getTick()+
|
m@0
|
191 // "; onset in microseconds = " +
|
m@0
|
192 // ticksToMicroseconds(event.getTick()));
|
JShulver@22
|
193 //if the event does not have a velocity of zero (i.e. switching a note off)
|
JShulver@22
|
194 if(message.getMessage()[2] != 0) {
|
JShulver@22
|
195 ons.add(ticksToMicroseconds(event.getTick())); //THEN we can add the note
|
JShulver@22
|
196 }
|
m@0
|
197 }
|
m@0
|
198 }
|
m@0
|
199 }
|
m@0
|
200 return ons;
|
m@0
|
201 }
|
m@0
|
202
|
m@0
|
203 /* compute a list of note offset times (microseconds) */
|
m@0
|
204 private ArrayList computeOffsets() {
|
m@0
|
205 ArrayList offs = new ArrayList();
|
m@0
|
206 Track[] tracks = sequence.getTracks();
|
m@0
|
207
|
m@0
|
208 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
|
m@0
|
209 Track track = tracks[nTrack];
|
m@0
|
210 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
|
m@0
|
211 MidiEvent event = track.get(nEvent);
|
m@0
|
212 MidiMessage message = event.getMessage();
|
m@0
|
213 if (message instanceof ShortMessage &&
|
m@0
|
214 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_OFF) {
|
m@0
|
215 //System.out.println("offset in ticks = " + event.getTick()+
|
m@0
|
216 // "; microsecondsPerTick = " + microsecondsPerTick +
|
m@0
|
217 // "; offset in microseconds = " +
|
m@0
|
218 // (float)event.getTick() * microsecondsPerTick);
|
m@0
|
219 offs.add(ticksToMicroseconds(event.getTick()));
|
m@0
|
220 }
|
JShulver@22
|
221 //if we have not found a note off,
|
JShulver@22
|
222 else if (message instanceof ShortMessage
|
JShulver@22
|
223 && ((ShortMessage)message).getCommand() == ShortMessage.NOTE_ON
|
JShulver@22
|
224 && message.getMessage()[2] == 0) { //but it is a note on with a velocity of zero
|
JShulver@22
|
225 offs.add(ticksToMicroseconds(event.getTick())); //add it as an off signal
|
JShulver@22
|
226 }
|
JShulver@22
|
227
|
m@0
|
228 }
|
m@0
|
229 }
|
m@0
|
230 return offs;
|
m@0
|
231 }
|
m@0
|
232
|
m@0
|
233 /* compute a list of note pitches */
|
m@0
|
234 private ArrayList computePitches() {
|
m@0
|
235 ArrayList pit = new ArrayList();
|
m@0
|
236 Track[] tracks = sequence.getTracks();
|
m@0
|
237
|
m@0
|
238 for (int nTrack = 0; nTrack < tracks.length; nTrack++) {
|
m@0
|
239 Track track = tracks[nTrack];
|
m@0
|
240 for (int nEvent = 0; nEvent < track.size(); nEvent++) {
|
m@0
|
241 MidiEvent event = track.get(nEvent);
|
m@0
|
242 MidiMessage message = event.getMessage();
|
m@0
|
243 if (message instanceof ShortMessage &&
|
m@0
|
244 ((ShortMessage)message).getCommand() == ShortMessage.NOTE_ON)
|
m@0
|
245 pit.add(((ShortMessage)message).getData1());
|
m@0
|
246 }
|
m@0
|
247 }
|
m@0
|
248 return pit;
|
m@0
|
249 }
|
m@0
|
250
|
jeremy@24
|
251 /*
|
jeremy@24
|
252 * Simultaneously construct lists of event onsets, offsets and pitches
|
jeremy@24
|
253 */
|
jeremy@24
|
254 private void registerEvents() {
|
jeremy@24
|
255 onsets = new ArrayList<Long>();
|
jeremy@24
|
256 offsets = new ArrayList<Long>();
|
jeremy@24
|
257 pitches = new ArrayList<Integer>();
|
jeremy@24
|
258 velocities = new ArrayList<Integer>();
|
jeremy@24
|
259
|
jeremy@24
|
260 Track[] tracks = sequence.getTracks();
|
jeremy@24
|
261
|
jeremy@24
|
262 // Iterate over MIDI tracks
|
jeremy@24
|
263 for (int i = 0; i < tracks.length; i++) {
|
jeremy@24
|
264 Track track = tracks[i];
|
jeremy@24
|
265 // Iterate over track events
|
jeremy@24
|
266 for (int j = 0; j < track.size(); j++) {
|
jeremy@24
|
267 registerEvent(i, j);
|
jeremy@24
|
268 }
|
jeremy@24
|
269 }
|
jeremy@24
|
270
|
jeremy@24
|
271 if (debug) {
|
jeremy@24
|
272 System.out.println("\nRegistered events...");
|
jeremy@24
|
273 Iterator<Long> oi = onsets.iterator();
|
jeremy@24
|
274 Iterator<Long> fi = offsets.iterator();
|
jeremy@24
|
275 Iterator<Integer> pi = pitches.iterator();
|
jeremy@24
|
276 Iterator<Integer> vi = velocities.iterator();
|
jeremy@24
|
277
|
jeremy@24
|
278 int pos = 1;
|
jeremy@24
|
279 while (oi.hasNext() && fi.hasNext() && pi.hasNext() && vi.hasNext()) {
|
jeremy@24
|
280 System.out.println("Event " + pos + ": onset " + oi.next() + ", offset " + fi.next()
|
jeremy@24
|
281 + ", pitch " + pi.next() + ", velocity " + vi.next());
|
jeremy@24
|
282 pos++;
|
jeremy@24
|
283 }
|
jeremy@24
|
284
|
jeremy@24
|
285 if (oi.hasNext() || fi.hasNext() || pi.hasNext() || vi.hasNext()) {
|
jeremy@24
|
286 System.out.println("Warning: event lists not equal length.");
|
jeremy@24
|
287 }
|
jeremy@24
|
288 }
|
jeremy@24
|
289 }
|
jeremy@24
|
290
|
jeremy@24
|
291 /*
|
jeremy@24
|
292 * Add the given event to the onset, offset and pitch lists.
|
jeremy@24
|
293 */
|
jeremy@24
|
294 private void registerEvent(int trackIndex, int eventIndex) {
|
jeremy@24
|
295
|
jeremy@24
|
296 Track track = sequence.getTracks()[trackIndex];
|
jeremy@24
|
297 MidiEvent event = track.get(eventIndex);
|
jeremy@24
|
298 MidiMessage message = event.getMessage();
|
jeremy@24
|
299
|
jeremy@24
|
300 // Register NOTE_ON events
|
jeremy@24
|
301 if (message instanceof ShortMessage) {
|
jeremy@24
|
302 ShortMessage shortMsg = (ShortMessage) message;
|
jeremy@24
|
303 int velocity = shortMsg.getData2();
|
jeremy@24
|
304
|
jeremy@24
|
305 if (shortMsg.getCommand() == ShortMessage.NOTE_ON && velocity != 0) {
|
jeremy@24
|
306
|
jeremy@24
|
307 long onset = ticksToMicroseconds(event.getTick());
|
jeremy@24
|
308 int pitch = shortMsg.getData1();
|
jeremy@24
|
309 long offset = getOffset(trackIndex, eventIndex, onset, pitch);
|
jeremy@24
|
310
|
jeremy@24
|
311 registerEvent(onset, offset, pitch, velocity);
|
jeremy@24
|
312 }
|
jeremy@24
|
313 }
|
jeremy@24
|
314 }
|
jeremy@24
|
315
|
jeremy@24
|
316 /*
|
jeremy@24
|
317 * Add the event details to the onset, offset and pitch lists,
|
jeremy@24
|
318 * use onset to determine the list position.
|
jeremy@24
|
319 */
|
jeremy@24
|
320 private void registerEvent(long onset, long offset, int pitch, int velocity) {
|
jeremy@24
|
321
|
jeremy@24
|
322 int index = 0;
|
jeremy@24
|
323 boolean inserted = false;
|
jeremy@24
|
324
|
jeremy@24
|
325 while (index < onsets.size()) {
|
jeremy@24
|
326
|
jeremy@24
|
327 if (onsets.get(index) > onset)
|
jeremy@24
|
328 break;
|
jeremy@24
|
329 else
|
jeremy@24
|
330 index++;
|
jeremy@24
|
331 }
|
jeremy@24
|
332
|
jeremy@24
|
333 onsets.add(index, onset);
|
jeremy@24
|
334 offsets.add(index, offset);
|
jeremy@24
|
335 pitches.add(index, pitch);
|
jeremy@24
|
336 velocities.add(index, pitch);
|
jeremy@24
|
337 }
|
jeremy@24
|
338
|
jeremy@24
|
339
|
jeremy@24
|
340
|
jeremy@24
|
341 /*
|
jeremy@24
|
342 * Find the matching NOTE_OFF event *after* the given NOTE_ON event
|
jeremy@24
|
343 * (the <onsetIndex>th event in track <trackNum>)
|
jeremy@24
|
344 */
|
jeremy@24
|
345 private long getOffset(int trackNum, int onsetIndex, long onsetTime, int pitch) {
|
jeremy@24
|
346
|
jeremy@24
|
347 long offset = -1;
|
jeremy@24
|
348 Track track = sequence.getTracks()[trackNum];
|
jeremy@24
|
349
|
jeremy@24
|
350 // Iterate through remaining events looking for NOTE_OFF
|
jeremy@24
|
351 for (int k = onsetIndex + 1; k < track.size(); k++) {
|
jeremy@24
|
352 MidiEvent event = track.get(k);
|
jeremy@24
|
353 MidiMessage message = event.getMessage();
|
jeremy@24
|
354
|
jeremy@24
|
355 if (message instanceof ShortMessage) {
|
jeremy@24
|
356 ShortMessage shortMsg = (ShortMessage) message;
|
jeremy@24
|
357 int command = shortMsg.getCommand();
|
jeremy@24
|
358
|
jeremy@24
|
359 // Check NOTE_OFF message
|
jeremy@24
|
360 if (command == ShortMessage.NOTE_OFF
|
jeremy@24
|
361 || (command == ShortMessage.NOTE_ON && shortMsg.getData2() == 0)) {
|
jeremy@24
|
362 int pitch2 = shortMsg.getData1();
|
jeremy@24
|
363 // If pitches are identical then offset found
|
jeremy@24
|
364 if (pitch == pitch2) {
|
jeremy@24
|
365 offset = ticksToMicroseconds(event.getTick());
|
jeremy@24
|
366 break;
|
jeremy@24
|
367 }
|
jeremy@24
|
368 }
|
jeremy@24
|
369 }
|
jeremy@24
|
370 }
|
jeremy@24
|
371
|
jeremy@24
|
372 if (offset < 0) {
|
jeremy@24
|
373 System.out.println("No NOTE_OFF found for track " + trackNum
|
jeremy@24
|
374 + ", onset " + onsetTime + ", pitch " + pitch);
|
jeremy@24
|
375 }
|
jeremy@24
|
376
|
jeremy@24
|
377 return offset;
|
jeremy@24
|
378 }
|
jeremy@24
|
379
|
jeremy@24
|
380
|
jeremy@24
|
381
|
m@0
|
382 /* return a list of note onset times (milliseconds) */
|
m@0
|
383 public ArrayList getOnsets() { return onsets; }
|
m@0
|
384
|
m@0
|
385 /* return a list of note offset times (milliseconds) */
|
m@0
|
386 public ArrayList getOffsets() { return offsets; }
|
m@0
|
387
|
m@0
|
388 /* return a list of note pitches */
|
m@0
|
389 public ArrayList getPitches() { return pitches; }
|
m@0
|
390
|
m@0
|
391 /* return a list of note durations (microseconds) */
|
m@0
|
392 public ArrayList getDurations() {
|
m@0
|
393 Object[] ons = onsets.toArray();
|
m@0
|
394 Object[] offs = offsets.toArray();
|
m@0
|
395
|
m@0
|
396 ArrayList durations = new ArrayList();
|
m@0
|
397
|
m@0
|
398 for(int i = 0; i < ons.length; i++) {
|
m@0
|
399 durations.add(((Long)offs[i]).longValue() -
|
m@0
|
400 ((Long)ons[i]).longValue());
|
m@0
|
401 }
|
m@0
|
402 return durations;
|
m@0
|
403 }
|
m@0
|
404
|
m@0
|
405 /* return a list of inter-onset intervals (microseconds) */
|
m@0
|
406 public ArrayList getInterOnsetIntervals() {
|
m@0
|
407 Object[] ons = onsets.toArray();
|
m@0
|
408
|
m@0
|
409 ArrayList iois = new ArrayList();
|
m@0
|
410 long firstIOI = 0;
|
m@0
|
411 iois.add(firstIOI); // IOI of first note is zero
|
m@0
|
412
|
m@0
|
413 for(int i = 1; i < ons.length; i++) {
|
m@0
|
414 iois.add(((Long)ons[i]).longValue() -
|
m@0
|
415 ((Long)ons[i-1]).longValue());
|
m@0
|
416 }
|
m@0
|
417 return iois;
|
m@0
|
418 }
|
m@0
|
419
|
m@0
|
420 /* return the length of a rest preceding a note */
|
m@0
|
421 public ArrayList getDeltaST() {
|
m@0
|
422 Object[] durs = getDurations().toArray();
|
m@0
|
423 Object[] iois = getInterOnsetIntervals().toArray();
|
m@0
|
424
|
m@0
|
425 ArrayList deltaST = new ArrayList();
|
m@0
|
426 long firstDeltaST = 0;
|
m@0
|
427 deltaST.add(firstDeltaST); // deltaST of first note is zero
|
m@0
|
428
|
m@0
|
429 for(int i = 1; i < durs.length; i++) {
|
m@0
|
430 deltaST.add(((Long)durs[i-1]).longValue() -
|
m@0
|
431 ((Long)iois[i]).longValue());
|
m@0
|
432 }
|
m@0
|
433 return deltaST;
|
m@0
|
434 }
|
m@0
|
435
|
jeremy@24
|
436 /*
|
jeremy@24
|
437 * Return the tatum of the midi file, i.e. the shortest
|
jeremy@24
|
438 * note duration or positive rest.
|
jeremy@24
|
439 */
|
JShulver@23
|
440 public long getTatum() {
|
JShulver@23
|
441
|
JShulver@23
|
442
|
m@0
|
443 Object[] durs = getDurations().toArray();
|
m@0
|
444 Object[] rests = getDeltaST().toArray();
|
m@0
|
445 long tatum = -1;
|
m@0
|
446
|
jeremy@24
|
447
|
m@0
|
448 for(int i = 0; i < durs.length; i++) {
|
m@0
|
449 long dur = ((Long)durs[i]).longValue();
|
m@0
|
450 long rest = ((Long)rests[i]).longValue();
|
m@0
|
451 long min = dur;
|
jeremy@24
|
452 if (rest > 0)
|
m@0
|
453 min = Math.min(dur, rest);
|
jeremy@24
|
454 if (debug)
|
jeremy@24
|
455 System.out.println("Dur: " + dur + " Rest: " + rest);
|
m@0
|
456 if (tatum < 0)
|
m@0
|
457 tatum = dur;
|
m@0
|
458 else if (min < tatum)
|
m@0
|
459 tatum = min;
|
m@0
|
460 }
|
JShulver@23
|
461 //tatum = sequence.getResolution()*1000;
|
m@0
|
462 return tatum;
|
m@0
|
463 }
|
m@0
|
464
|
m@0
|
465 /* return length of sequence in microseconds */
|
m@0
|
466 public long getLength() {
|
m@0
|
467 return sequence.getMicrosecondLength();
|
m@0
|
468 }
|
m@0
|
469
|
m@0
|
470 /* play the midi file */
|
m@0
|
471 public void play() {
|
marcus@16
|
472 //System.out.println("MidiPlayer.play: run sequencer.start().");
|
m@0
|
473 sequencer.start();
|
m@0
|
474 }
|
m@0
|
475
|
m@0
|
476 public void stop() {
|
m@4
|
477 if (synthesizer != null) {
|
m@4
|
478 synthesizer.close();
|
m@4
|
479 }
|
m@4
|
480 if (sequencer != null) {
|
m@4
|
481 sequencer.close();
|
m@4
|
482 }
|
m@4
|
483 sequencer = null;
|
m@4
|
484 synthesizer = null;
|
m@4
|
485 }
|
m@0
|
486 }
|