Chris@2
|
1 /*
|
Chris@2
|
2 Copyright (C) 2001, 2006 by Simon Dixon
|
Chris@2
|
3
|
Chris@2
|
4 This program is free software; you can redistribute it and/or modify
|
Chris@2
|
5 it under the terms of the GNU General Public License as published by
|
Chris@2
|
6 the Free Software Foundation; either version 2 of the License, or
|
Chris@2
|
7 (at your option) any later version.
|
Chris@2
|
8
|
Chris@2
|
9 This program is distributed in the hope that it will be useful,
|
Chris@2
|
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@2
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@2
|
12 GNU General Public License for more details.
|
Chris@2
|
13
|
Chris@2
|
14 You should have received a copy of the GNU General Public License along
|
Chris@2
|
15 with this program (the file gpl.txt); if not, download it from
|
Chris@2
|
16 http://www.gnu.org/licenses/gpl.txt or write to the
|
Chris@2
|
17 Free Software Foundation, Inc.,
|
Chris@2
|
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
Chris@2
|
19 */
|
Chris@2
|
20
|
Chris@2
|
21 package at.ofai.music.util;
|
Chris@2
|
22
|
Chris@2
|
23 import java.io.BufferedReader;
|
Chris@2
|
24 import java.io.File;
|
Chris@2
|
25 import java.io.FileInputStream;
|
Chris@2
|
26 import java.io.FileOutputStream;
|
Chris@2
|
27 import java.io.FileReader;
|
Chris@2
|
28 import java.io.IOException;
|
Chris@2
|
29 import java.io.ObjectInputStream;
|
Chris@2
|
30 import java.io.ObjectOutputStream;
|
Chris@2
|
31 import java.io.PrintStream;
|
Chris@2
|
32 import java.io.Serializable;
|
Chris@2
|
33 import java.util.Iterator;
|
Chris@2
|
34 import java.util.LinkedList;
|
Chris@2
|
35 import java.util.ListIterator;
|
Chris@2
|
36
|
Chris@2
|
37 import javax.sound.midi.InvalidMidiDataException;
|
Chris@2
|
38 import javax.sound.midi.MetaMessage;
|
Chris@2
|
39 import javax.sound.midi.MidiEvent;
|
Chris@2
|
40 import javax.sound.midi.MidiMessage;
|
Chris@2
|
41 import javax.sound.midi.MidiSystem;
|
Chris@2
|
42 import javax.sound.midi.Sequence;
|
Chris@2
|
43 import javax.sound.midi.ShortMessage;
|
Chris@2
|
44 import javax.sound.midi.Track;
|
Chris@2
|
45
|
Chris@2
|
46 import at.ofai.music.worm.Worm;
|
Chris@2
|
47 import at.ofai.music.worm.WormFile;
|
Chris@2
|
48 import at.ofai.music.worm.WormParameters;
|
Chris@2
|
49
|
Chris@2
|
50 // Adapted from eventList::readMatchFile in beatroot/src/eventMidi.cpp
|
Chris@2
|
51
|
Chris@2
|
52 // Reads in a Prolog score+performance (.match) file; returns it as an eventList
|
Chris@2
|
53 // Lines in the match file can be of the form:
|
Chris@2
|
54 // hammer_bounce-PlayedNote.
|
Chris@2
|
55 // info(Attribute, Value).
|
Chris@2
|
56 // insertion-PlayedNote.
|
Chris@2
|
57 // ornament(Anchor)-PlayedNote.
|
Chris@2
|
58 // ScoreNote-deletion.
|
Chris@2
|
59 // ScoreNote-PlayedNote.
|
Chris@2
|
60 // ScoreNote-trailing_score_note.
|
Chris@2
|
61 // trailing_played_note-PlayedNote.
|
Chris@2
|
62 // trill(Anchor)-PlayedNote.
|
Chris@2
|
63 // where ScoreNote is of the form
|
Chris@2
|
64 // snote(Anchor,[NoteName,Modifier],Octave,Bar:Beat,Offset,Duration,
|
Chris@2
|
65 // BeatNumber,DurationInBeats,ScoreAttributesList)
|
Chris@2
|
66 // e.g. snote(n1,[b,b],5,1:1,0,3/16,0,0.75,[s])
|
Chris@2
|
67 // and PlayedNote is of the form
|
Chris@2
|
68 // note(Number,[NoteName,Modifier],Octave,Onset,Offset,AdjOffset,Velocity)
|
Chris@2
|
69 // e.g. note(1,[a,#],5,5054,6362,6768,53)
|
Chris@2
|
70
|
Chris@2
|
71 class WormFileParseException extends RuntimeException {
|
Chris@2
|
72
|
Chris@2
|
73 static final long serialVersionUID = 0;
|
Chris@2
|
74 public WormFileParseException(String s) {
|
Chris@2
|
75 super(s);
|
Chris@2
|
76 } // constructor
|
Chris@2
|
77
|
Chris@2
|
78 } // class WormFileParseException
|
Chris@2
|
79
|
Chris@2
|
80 class MatchFileParseException extends RuntimeException {
|
Chris@2
|
81
|
Chris@2
|
82 static final long serialVersionUID = 0;
|
Chris@2
|
83 public MatchFileParseException(String s) {
|
Chris@2
|
84 super(s);
|
Chris@2
|
85 } // constructor
|
Chris@2
|
86
|
Chris@2
|
87 } // class MatchFileParseException
|
Chris@2
|
88
|
Chris@2
|
89 class BTFileParseException extends RuntimeException {
|
Chris@2
|
90
|
Chris@2
|
91 static final long serialVersionUID = 0;
|
Chris@2
|
92 public BTFileParseException(String s) {
|
Chris@2
|
93 super(s);
|
Chris@2
|
94 } // constructor
|
Chris@2
|
95
|
Chris@2
|
96 } // class BTFileParseException
|
Chris@2
|
97
|
Chris@2
|
98
|
Chris@2
|
99 // Process the strings which label extra features of notes in match files.
|
Chris@2
|
100 // We assume no more than 32 distinct labels in a file.
|
Chris@2
|
101 class Flags {
|
Chris@2
|
102
|
Chris@2
|
103 String[] labels = new String[32];
|
Chris@2
|
104 int size = 0;
|
Chris@2
|
105
|
Chris@2
|
106 int getFlag(String s) {
|
Chris@2
|
107 if ((s == null) || s.equals(""))
|
Chris@2
|
108 return 0;
|
Chris@2
|
109 //int val = 1;
|
Chris@2
|
110 for (int i = 0; i < size; i++)
|
Chris@2
|
111 if (s.equals(labels[i]))
|
Chris@2
|
112 return 1 << i;
|
Chris@2
|
113 if (size == 32) {
|
Chris@2
|
114 System.err.println("Overflow: Too many flags: " + s);
|
Chris@2
|
115 size--;
|
Chris@2
|
116 }
|
Chris@2
|
117 labels[size] = s;
|
Chris@2
|
118 return 1 << size++;
|
Chris@2
|
119 } // getFlag()
|
Chris@2
|
120
|
Chris@2
|
121 String getLabel(int i) {
|
Chris@2
|
122 if (i >= size)
|
Chris@2
|
123 return "ERROR: Unknown flag";
|
Chris@2
|
124 return labels[i];
|
Chris@2
|
125 } // getLabel()
|
Chris@2
|
126
|
Chris@2
|
127 } // class Flags
|
Chris@2
|
128
|
Chris@2
|
129
|
Chris@2
|
130 // A score/match/midi file is represented as an EventList object,
|
Chris@2
|
131 // which contains pointers to the head and tail links, and some
|
Chris@2
|
132 // class-wide parameters. Parameters are class-wide, as it is
|
Chris@2
|
133 // assumed that the Worm has only one input file at a time.
|
Chris@2
|
134 public class EventList implements Serializable {
|
Chris@2
|
135
|
Chris@2
|
136 public LinkedList<Event> l;
|
Chris@2
|
137
|
Chris@2
|
138 protected static boolean timingCorrection = false;
|
Chris@2
|
139 protected static double timingDisplacement = 0;
|
Chris@2
|
140 protected static int clockUnits = 480;
|
Chris@2
|
141 protected static int clockRate = 500000;
|
Chris@2
|
142 protected static double metricalLevel = 0;
|
Chris@2
|
143 public static final double UNKNOWN = Double.NaN;
|
Chris@2
|
144 protected static boolean noMelody = false;
|
Chris@2
|
145 protected static boolean onlyMelody = false;
|
Chris@2
|
146 protected static Flags flags = new Flags();
|
Chris@2
|
147
|
Chris@2
|
148 public EventList() {
|
Chris@2
|
149 l = new LinkedList<Event>();
|
Chris@2
|
150 } // constructor
|
Chris@2
|
151
|
Chris@2
|
152 public EventList(EventList e) {
|
Chris@2
|
153 this();
|
Chris@2
|
154 ListIterator<Event> it = e.listIterator();
|
Chris@2
|
155 while (it.hasNext())
|
Chris@2
|
156 add(it.next());
|
Chris@2
|
157 } // constructor
|
Chris@2
|
158
|
Chris@2
|
159 public EventList(Event[] e) {
|
Chris@2
|
160 this();
|
Chris@2
|
161 for (int i=0; i < e.length; i++)
|
Chris@2
|
162 add(e[i]);
|
Chris@2
|
163 } // constructor
|
Chris@2
|
164
|
Chris@2
|
165 public void add(Event e) {
|
Chris@2
|
166 l.add(e);
|
Chris@2
|
167 } // add()
|
Chris@2
|
168
|
Chris@2
|
169 public void add(EventList ev) {
|
Chris@2
|
170 l.addAll(ev.l);
|
Chris@2
|
171 } // add()
|
Chris@2
|
172
|
Chris@2
|
173 public void insert(Event newEvent, boolean uniqueTimes) {
|
Chris@2
|
174 ListIterator<Event> li = l.listIterator();
|
Chris@2
|
175 while (li.hasNext()) {
|
Chris@2
|
176 int sgn = newEvent.compareTo(li.next());
|
Chris@2
|
177 if (sgn < 0) {
|
Chris@2
|
178 li.previous();
|
Chris@2
|
179 break;
|
Chris@2
|
180 } else if (uniqueTimes && (sgn == 0)) {
|
Chris@2
|
181 li.remove();
|
Chris@2
|
182 break;
|
Chris@2
|
183 }
|
Chris@2
|
184 }
|
Chris@2
|
185 li.add(newEvent);
|
Chris@2
|
186 } // insert()
|
Chris@2
|
187
|
Chris@2
|
188 public ListIterator<Event> listIterator() {
|
Chris@2
|
189 return l.listIterator();
|
Chris@2
|
190 } // listIterator()
|
Chris@2
|
191
|
Chris@2
|
192 public Iterator<Event> iterator() {
|
Chris@2
|
193 return l.iterator();
|
Chris@2
|
194 } // iterator()
|
Chris@2
|
195
|
Chris@2
|
196 public int size() {
|
Chris@2
|
197 return l.size();
|
Chris@2
|
198 } // size()
|
Chris@2
|
199
|
Chris@2
|
200 public Event[] toArray() {
|
Chris@2
|
201 return toArray(0);
|
Chris@2
|
202 } // toArray()
|
Chris@2
|
203
|
Chris@2
|
204 public double[] toOnsetArray() {
|
Chris@2
|
205 double[] d = new double[l.size()];
|
Chris@2
|
206 int i = 0;
|
Chris@2
|
207 for (Iterator<Event> it = l.iterator(); it.hasNext(); i++)
|
Chris@2
|
208 d[i] = it.next().keyDown;
|
Chris@2
|
209 return d;
|
Chris@2
|
210 } // toOnsetArray()
|
Chris@2
|
211
|
Chris@2
|
212 public Event[] toArray(int match) {
|
Chris@2
|
213 int count = 0;
|
Chris@2
|
214 for (Event e : l)
|
Chris@2
|
215 if ((match == 0) || (e.midiCommand == match))
|
Chris@2
|
216 count++;
|
Chris@2
|
217 Event[] a = new Event[count];
|
Chris@2
|
218 int i = 0;
|
Chris@2
|
219 for (Event e : l)
|
Chris@2
|
220 if ((match == 0) || (e.midiCommand == match))
|
Chris@2
|
221 a[i++] = e;
|
Chris@2
|
222 return a;
|
Chris@2
|
223 } // toArray()
|
Chris@2
|
224
|
Chris@2
|
225 public void writeBinary(String fileName) {
|
Chris@2
|
226 try {
|
Chris@2
|
227 ObjectOutputStream oos = new ObjectOutputStream(
|
Chris@2
|
228 new FileOutputStream(fileName));
|
Chris@2
|
229 oos.writeObject(this);
|
Chris@2
|
230 oos.close();
|
Chris@2
|
231 } catch (IOException e) {
|
Chris@2
|
232 System.err.println(e);
|
Chris@2
|
233 }
|
Chris@2
|
234 } // writeBinary()
|
Chris@2
|
235
|
Chris@2
|
236 public static EventList readBinary(String fileName) {
|
Chris@2
|
237 try {
|
Chris@2
|
238 ObjectInputStream ois = new ObjectInputStream(
|
Chris@2
|
239 new FileInputStream(fileName));
|
Chris@2
|
240 EventList e = (EventList) ois.readObject();
|
Chris@2
|
241 ois.close();
|
Chris@2
|
242 return e;
|
Chris@2
|
243 } catch (IOException e) {
|
Chris@2
|
244 System.err.println(e);
|
Chris@2
|
245 return null;
|
Chris@2
|
246 } catch (ClassNotFoundException e) {
|
Chris@2
|
247 System.err.println(e);
|
Chris@2
|
248 return null;
|
Chris@2
|
249 }
|
Chris@2
|
250 } // readBinary()
|
Chris@2
|
251
|
Chris@2
|
252 public void writeMIDI(String fileName) {
|
Chris@2
|
253 writeMIDI(fileName, null);
|
Chris@2
|
254 } // writeMIDI()
|
Chris@2
|
255
|
Chris@2
|
256 public void writeMIDI(String fileName, EventList pedal) {
|
Chris@2
|
257 try {
|
Chris@2
|
258 MidiSystem.write(toMIDI(pedal), 1, new File(fileName));
|
Chris@2
|
259 } catch (Exception e) {
|
Chris@2
|
260 System.err.println("Error: Unable to write MIDI file " + fileName);
|
Chris@2
|
261 e.printStackTrace();
|
Chris@2
|
262 }
|
Chris@2
|
263 } // writeMIDI()
|
Chris@2
|
264
|
Chris@2
|
265 public Sequence toMIDI(EventList pedal) throws InvalidMidiDataException {
|
Chris@2
|
266 final int midiTempo = 1000000;
|
Chris@2
|
267 Sequence s = new Sequence(Sequence.PPQ, 1000);
|
Chris@2
|
268 Track[] tr = new Track[16];
|
Chris@2
|
269 tr[0] = s.createTrack();
|
Chris@2
|
270 MetaMessage mm = new MetaMessage();
|
Chris@2
|
271 byte[] b = new byte[3];
|
Chris@2
|
272 b[0] = (byte)((midiTempo >> 16) & 0xFF);
|
Chris@2
|
273 b[1] = (byte)((midiTempo >> 8) & 0xFF);
|
Chris@2
|
274 b[2] = (byte)(midiTempo & 0xFF);
|
Chris@2
|
275 mm.setMessage(0x51, b, 3);
|
Chris@2
|
276 tr[0].add(new MidiEvent(mm, 0L));
|
Chris@2
|
277 for (Event e : l) { // from match or beatTrack file
|
Chris@2
|
278 if (e.midiCommand == 0) // skip beatTrack file
|
Chris@2
|
279 break;
|
Chris@2
|
280 if (tr[e.midiTrack] == null)
|
Chris@2
|
281 tr[e.midiTrack] = s.createTrack();
|
Chris@2
|
282 //switch (e.midiCommand)
|
Chris@2
|
283 //case ShortMessage.NOTE_ON:
|
Chris@2
|
284 //case ShortMessage.POLY_PRESSURE:
|
Chris@2
|
285 //case ShortMessage.CONTROL_CHANGE:
|
Chris@2
|
286 //case ShortMessage.PROGRAM_CHANGE:
|
Chris@2
|
287 //case ShortMessage.CHANNEL_PRESSURE:
|
Chris@2
|
288 //case ShortMessage.PITCH_BEND:
|
Chris@2
|
289 ShortMessage sm = new ShortMessage();
|
Chris@2
|
290 sm.setMessage(e.midiCommand, e.midiChannel,
|
Chris@2
|
291 e.midiPitch, e.midiVelocity);
|
Chris@2
|
292 tr[e.midiTrack].add(new MidiEvent(sm,
|
Chris@2
|
293 (long)Math.round(1000 * e.keyDown)));
|
Chris@2
|
294 if (e.midiCommand == ShortMessage.NOTE_ON) {
|
Chris@2
|
295 sm = new ShortMessage();
|
Chris@2
|
296 sm.setMessage(ShortMessage.NOTE_OFF, e.midiChannel, e.midiPitch, 0);
|
Chris@2
|
297 tr[e.midiTrack].add(new MidiEvent(sm, (long)Math.round(1000 * e.keyUp)));
|
Chris@2
|
298 }
|
Chris@2
|
299 }
|
Chris@2
|
300 if (pedal != null) { // from MIDI file
|
Chris@2
|
301 // if (t.size() > 0) // otherwise beatTrack files leave an empty trk
|
Chris@2
|
302 // t = s.createTrack();
|
Chris@2
|
303 for (Event e : pedal.l) {
|
Chris@2
|
304 if (tr[e.midiTrack] == null)
|
Chris@2
|
305 tr[e.midiTrack] = s.createTrack();
|
Chris@2
|
306 ShortMessage sm = new ShortMessage();
|
Chris@2
|
307 sm.setMessage(e.midiCommand, e.midiChannel,
|
Chris@2
|
308 e.midiPitch, e.midiVelocity);
|
Chris@2
|
309 tr[e.midiTrack].add(new MidiEvent(sm,
|
Chris@2
|
310 (long)Math.round(1000 * e.keyDown)));
|
Chris@2
|
311 if (e.midiCommand == ShortMessage.NOTE_ON) {
|
Chris@2
|
312 sm = new ShortMessage();
|
Chris@2
|
313 sm.setMessage(ShortMessage.NOTE_OFF, e.midiChannel,
|
Chris@2
|
314 e.midiPitch,e.midiVelocity);
|
Chris@2
|
315 tr[e.midiTrack].add(new MidiEvent(sm,
|
Chris@2
|
316 (long)Math.round(1000 * e.keyUp)));
|
Chris@2
|
317 }
|
Chris@2
|
318 //catch (InvalidMidiDataException exception) {}
|
Chris@2
|
319 }
|
Chris@2
|
320 }
|
Chris@2
|
321 return s;
|
Chris@2
|
322 } // toMIDI()
|
Chris@2
|
323
|
Chris@2
|
324 public static EventList readMidiFile(String fileName) {
|
Chris@2
|
325 return readMidiFile(fileName, 0);
|
Chris@2
|
326 } // readMidiFile()
|
Chris@2
|
327
|
Chris@2
|
328 public static EventList readMidiFile(String fileName, int skipTrackFlag) {
|
Chris@2
|
329 EventList list = new EventList();
|
Chris@2
|
330 Sequence s;
|
Chris@2
|
331 try {
|
Chris@2
|
332 s = MidiSystem.getSequence(new File(fileName));
|
Chris@2
|
333 } catch (Exception e) {
|
Chris@2
|
334 e.printStackTrace();
|
Chris@2
|
335 return list;
|
Chris@2
|
336 }
|
Chris@2
|
337 double midiTempo = 500000;
|
Chris@2
|
338 double tempoFactor = midiTempo / s.getResolution() / 1000000.0;
|
Chris@2
|
339 // System.err.println(tempoFactor);
|
Chris@2
|
340 Event[][] noteOns = new Event[128][16];
|
Chris@2
|
341 Track[] tracks = s.getTracks();
|
Chris@2
|
342 for (int t = 0; t < tracks.length; t++, skipTrackFlag >>= 1) {
|
Chris@2
|
343 if ((skipTrackFlag & 1) == 1)
|
Chris@2
|
344 continue;
|
Chris@2
|
345 for (int e = 0; e < tracks[t].size(); e++) {
|
Chris@2
|
346 MidiEvent me = tracks[t].get(e);
|
Chris@2
|
347 MidiMessage mm = me.getMessage();
|
Chris@2
|
348 double time = me.getTick() * tempoFactor;
|
Chris@2
|
349 byte[] mesg = mm.getMessage();
|
Chris@2
|
350 int channel = mesg[0] & 0x0F;
|
Chris@2
|
351 int command = mesg[0] & 0xF0;
|
Chris@2
|
352 if (command == ShortMessage.NOTE_ON) {
|
Chris@2
|
353 int pitch = mesg[1] & 0x7F;
|
Chris@2
|
354 int velocity = mesg[2] & 0x7F;
|
Chris@2
|
355 if (noteOns[pitch][channel] != null) {
|
Chris@2
|
356 if (velocity == 0) { // NOTE_OFF in disguise :(
|
Chris@2
|
357 noteOns[pitch][channel].keyUp = time;
|
Chris@2
|
358 noteOns[pitch][channel].pedalUp = time;
|
Chris@2
|
359 noteOns[pitch][channel] = null;
|
Chris@2
|
360 } else
|
Chris@2
|
361 System.err.println("Double note on: n=" + pitch +
|
Chris@2
|
362 " c=" + channel +
|
Chris@2
|
363 " t1=" + noteOns[pitch][channel] +
|
Chris@2
|
364 " t2=" + time);
|
Chris@2
|
365 } else {
|
Chris@2
|
366 Event n = new Event(time, 0, 0, pitch, velocity, -1, -1,
|
Chris@2
|
367 0, ShortMessage.NOTE_ON, channel, t);
|
Chris@2
|
368 noteOns[pitch][channel] = n;
|
Chris@2
|
369 list.add(n);
|
Chris@2
|
370 }
|
Chris@2
|
371 } else if (command == ShortMessage.NOTE_OFF) {
|
Chris@2
|
372 int pitch = mesg[1] & 0x7F;
|
Chris@2
|
373 noteOns[pitch][channel].keyUp = time;
|
Chris@2
|
374 noteOns[pitch][channel].pedalUp = time;
|
Chris@2
|
375 noteOns[pitch][channel] = null;
|
Chris@2
|
376 } else if (command == 0xF0) {
|
Chris@2
|
377 if ((channel == 0x0F) && (mesg[1] == 0x51)) {
|
Chris@2
|
378 midiTempo = (mesg[5] & 0xFF) |
|
Chris@2
|
379 ((mesg[4] & 0xFF) << 8) |
|
Chris@2
|
380 ((mesg[3] & 0xFF) << 16);
|
Chris@2
|
381 tempoFactor = midiTempo / s.getResolution() / 1000000.0;
|
Chris@2
|
382 // System.err.println("Info: Tempo change: " + midiTempo +
|
Chris@2
|
383 // " tf=" + tempoFactor);
|
Chris@2
|
384 }
|
Chris@2
|
385 } else if (mesg.length > 3) {
|
Chris@2
|
386 System.err.println("midi message too long: " + mesg.length);
|
Chris@2
|
387 System.err.println("\tFirst byte: " + mesg[0]);
|
Chris@2
|
388 } else {
|
Chris@2
|
389 int b0 = mesg[0] & 0xFF;
|
Chris@2
|
390 int b1 = -1;
|
Chris@2
|
391 int b2 = -1;
|
Chris@2
|
392 if (mesg.length > 1)
|
Chris@2
|
393 b1 = mesg[1] & 0xFF;
|
Chris@2
|
394 if (mesg.length > 2)
|
Chris@2
|
395 b2 = mesg[2] & 0xFF;
|
Chris@2
|
396 list.add(new Event(time, time, -1, b1, b2, -1, -1, 0,
|
Chris@2
|
397 b0 & 0xF0, b0 & 0x0F, t));
|
Chris@2
|
398 }
|
Chris@2
|
399 }
|
Chris@2
|
400 }
|
Chris@2
|
401 for (int pitch = 0; pitch < 128; pitch++)
|
Chris@2
|
402 for (int channel = 0; channel < 16; channel++)
|
Chris@2
|
403 if (noteOns[pitch][channel] != null)
|
Chris@2
|
404 System.err.println("Missing note off: n=" +
|
Chris@2
|
405 noteOns[pitch][channel].midiPitch + " t=" +
|
Chris@2
|
406 noteOns[pitch][channel].keyDown);
|
Chris@2
|
407 return list;
|
Chris@2
|
408 } // readMidiFile()
|
Chris@2
|
409
|
Chris@2
|
410 public void print() {
|
Chris@2
|
411 for (Iterator<Event> i = l.iterator(); i.hasNext(); )
|
Chris@2
|
412 i.next().print(flags);
|
Chris@2
|
413 } // print()
|
Chris@2
|
414
|
Chris@2
|
415 public static void setTimingCorrection(double corr) {
|
Chris@2
|
416 timingCorrection = corr >= 0;
|
Chris@2
|
417 timingDisplacement = corr;
|
Chris@2
|
418 } // setTimingCorrection()
|
Chris@2
|
419
|
Chris@2
|
420 public static EventList readBeatsAsText(String fileName) throws Exception {
|
Chris@2
|
421 EventList list = new EventList();
|
Chris@2
|
422 BufferedReader inputFile = new BufferedReader(new FileReader(fileName));
|
Chris@2
|
423 String s = inputFile.readLine();
|
Chris@2
|
424 if (s.startsWith("###"))
|
Chris@2
|
425 return readLabelFile(fileName);
|
Chris@2
|
426 int beats = 0;
|
Chris@2
|
427 int pitch = 56;
|
Chris@2
|
428 int vol = 80;
|
Chris@2
|
429 int ch = 10;
|
Chris@2
|
430 int track = 0;
|
Chris@2
|
431 int fl = 1;
|
Chris@2
|
432 while (s != null) {
|
Chris@2
|
433 int ind = s.indexOf(',');
|
Chris@2
|
434 if (ind < 0)
|
Chris@2
|
435 ind = s.indexOf(' ');
|
Chris@2
|
436 double time = 0;
|
Chris@2
|
437 if (ind >= 0) {
|
Chris@2
|
438 String tmp = s.substring(0,ind).trim();
|
Chris@2
|
439 if (tmp.length() == 0) {
|
Chris@2
|
440 s = inputFile.readLine();
|
Chris@2
|
441 continue;
|
Chris@2
|
442 }
|
Chris@2
|
443 time = Double.parseDouble(tmp);
|
Chris@2
|
444 s = s.substring(ind+1);
|
Chris@2
|
445 } else {
|
Chris@2
|
446 String tmp = s.trim();
|
Chris@2
|
447 if (tmp.length() > 0)
|
Chris@2
|
448 time = Double.parseDouble(tmp);
|
Chris@2
|
449 s = inputFile.readLine();
|
Chris@2
|
450 }
|
Chris@2
|
451 list.add(new Event(time, time, time, pitch, vol, ++beats,
|
Chris@2
|
452 1.0, fl, ShortMessage.NOTE_ON, ch, track));
|
Chris@2
|
453 }
|
Chris@2
|
454 return list;
|
Chris@2
|
455 } // readBeatsAsText()
|
Chris@2
|
456
|
Chris@2
|
457 public static EventList readBeatTrackFile(String fileName) throws Exception{
|
Chris@2
|
458 if (!fileName.endsWith(".tmf")) // || fileName.endsWith(".csv"))
|
Chris@2
|
459 return readBeatsAsText(fileName);
|
Chris@2
|
460 else {
|
Chris@2
|
461 EventList list = new EventList();
|
Chris@2
|
462 BufferedReader inputFile = new BufferedReader(new FileReader(fileName));
|
Chris@2
|
463 Matcher s = new Matcher(inputFile.readLine());
|
Chris@2
|
464 if (!s.matchString("MFile"))
|
Chris@2
|
465 throw new BTFileParseException("Header not found");
|
Chris@2
|
466 s.getInt(); // skip fileType
|
Chris@2
|
467 int tracks = s.getInt();
|
Chris@2
|
468 int div = s.getInt();
|
Chris@2
|
469 int tempo = 500000; // default tempo
|
Chris@2
|
470 double tf = 1e6 / tempo * div;
|
Chris@2
|
471 int lineCount = 1;
|
Chris@2
|
472 int beats = 0;
|
Chris@2
|
473 for (int track = 0; track < tracks; track++) {
|
Chris@2
|
474 s.set(inputFile.readLine());
|
Chris@2
|
475 lineCount++;
|
Chris@2
|
476 if (!s.matchString("MTrk"))
|
Chris@2
|
477 throw new BTFileParseException("MTrk not found");
|
Chris@2
|
478 s.set(inputFile.readLine());
|
Chris@2
|
479 lineCount++;
|
Chris@2
|
480 while (!s.matchString("TrkEnd")) {
|
Chris@2
|
481 double time = s.getInt() / tf;
|
Chris@2
|
482 s.trimSpace();
|
Chris@2
|
483 if (s.matchString("Tempo")) {
|
Chris@2
|
484 tempo = s.getInt();
|
Chris@2
|
485 tf = 1e6 / tempo * div;
|
Chris@2
|
486 } else if (s.matchString("On")) {
|
Chris@2
|
487 s.trimSpace();
|
Chris@2
|
488 s.matchString("ch=");
|
Chris@2
|
489 int ch = s.getInt();
|
Chris@2
|
490 s.trimSpace();
|
Chris@2
|
491 if (!s.matchString("n="))
|
Chris@2
|
492 s.matchString("note=");
|
Chris@2
|
493 int pitch = s.getInt();
|
Chris@2
|
494 s.trimSpace();
|
Chris@2
|
495 if (!s.matchString("v="))
|
Chris@2
|
496 s.matchString("vol=");
|
Chris@2
|
497 int vol = s.getInt();
|
Chris@2
|
498 s.set(inputFile.readLine());
|
Chris@2
|
499 lineCount++;
|
Chris@2
|
500 s.getInt();
|
Chris@2
|
501 s.trimSpace();
|
Chris@2
|
502 s.matchString("Off");
|
Chris@2
|
503 s.skip('v');
|
Chris@2
|
504 s.matchString("ol");
|
Chris@2
|
505 s.matchString("=");
|
Chris@2
|
506 int flags = s.getInt();
|
Chris@2
|
507 list.add(new Event(time, time, time, pitch, vol, ++beats,
|
Chris@2
|
508 1.0, flags, ShortMessage.NOTE_ON, ch, track));
|
Chris@2
|
509 } else if (!s.matchString("Meta TrkEnd")) {
|
Chris@2
|
510 System.err.println("Unmatched text on line " + lineCount +
|
Chris@2
|
511 ": " + s.get());
|
Chris@2
|
512 }
|
Chris@2
|
513 s.set(inputFile.readLine());
|
Chris@2
|
514 lineCount++;
|
Chris@2
|
515 }
|
Chris@2
|
516 }
|
Chris@2
|
517 return list;
|
Chris@2
|
518 }
|
Chris@2
|
519 } // readBeatTrackFile()
|
Chris@2
|
520
|
Chris@2
|
521 public void writeBeatsAsText(String fileName) throws Exception {
|
Chris@2
|
522 PrintStream out = new PrintStream(new File(fileName));
|
Chris@2
|
523 char separator = '\n';
|
Chris@2
|
524 if (fileName.endsWith(".csv"))
|
Chris@2
|
525 separator = ',';
|
Chris@2
|
526 for (Iterator<Event> it = iterator(); it.hasNext(); ) {
|
Chris@2
|
527 Event e = it.next();
|
Chris@2
|
528 out.printf("%5.3f%c", e.keyDown, it.hasNext()? separator: '\n');
|
Chris@2
|
529 }
|
Chris@2
|
530 out.close();
|
Chris@2
|
531 } // writeBeatsAsText()
|
Chris@2
|
532
|
Chris@2
|
533 public void writeBeatTrackFile(String fileName) throws Exception {
|
Chris@2
|
534 if (fileName.endsWith(".txt") || fileName.endsWith(".csv"))
|
Chris@2
|
535 writeBeatsAsText(fileName);
|
Chris@2
|
536 else {
|
Chris@2
|
537 PrintStream out = new PrintStream(new File(fileName));
|
Chris@2
|
538 out.println("MFile 0 1 500");
|
Chris@2
|
539 out.println("MTrk");
|
Chris@2
|
540 out.println(" 0 Tempo 500000");
|
Chris@2
|
541 int time = 0;
|
Chris@2
|
542 for (Iterator<Event> it = iterator(); it.hasNext(); ) {
|
Chris@2
|
543 Event e = it.next();
|
Chris@2
|
544 time = (int) Math.round(1000 * e.keyDown);
|
Chris@2
|
545 out.printf("%6d On ch=%3d n=%3d v=%3d\n",
|
Chris@2
|
546 time, e.midiChannel, e.midiPitch, e.midiVelocity);
|
Chris@2
|
547 out.printf("%6d Off ch=%3d n=%3d v=%3d\n",
|
Chris@2
|
548 time, e.midiChannel, e.midiPitch, e.flags);
|
Chris@2
|
549 }
|
Chris@2
|
550 out.printf("%6d Meta TrkEnd\nTrkEnd\n", time);
|
Chris@2
|
551 out.close();
|
Chris@2
|
552 }
|
Chris@2
|
553 } // writeBeatTrackFile()
|
Chris@2
|
554
|
Chris@2
|
555 /** Reads a file containing time,String pairs into an EventList. */
|
Chris@2
|
556 public static EventList readLabelFile(String fileName) throws Exception {
|
Chris@2
|
557 EventList list = new EventList();
|
Chris@2
|
558 BufferedReader inputFile = new BufferedReader(new FileReader(fileName));
|
Chris@2
|
559 Matcher s = new Matcher(inputFile.readLine());
|
Chris@2
|
560 int prevBar = 0;
|
Chris@2
|
561 int beats = 0;
|
Chris@2
|
562 int pitch = 56;
|
Chris@2
|
563 int vol = 80;
|
Chris@2
|
564 int ch = 10;
|
Chris@2
|
565 int track = 0;
|
Chris@2
|
566 while (s.hasData()) {
|
Chris@2
|
567 if (!s.matchString("#")) {
|
Chris@2
|
568 double time = s.getDouble();
|
Chris@2
|
569 String label = s.get().trim();
|
Chris@2
|
570 int colon = label.indexOf(':');
|
Chris@2
|
571 int beat = 0;
|
Chris@2
|
572 if (colon < 0)
|
Chris@2
|
573 colon = label.length();
|
Chris@2
|
574 else
|
Chris@2
|
575 beat = Integer.parseInt(label.substring(colon+1));
|
Chris@2
|
576 int bar = Integer.parseInt(label.substring(0, colon));
|
Chris@2
|
577 int flags = WormFile.BEAT;
|
Chris@2
|
578 if (bar != prevBar) {
|
Chris@2
|
579 flags |= WormFile.BAR;
|
Chris@2
|
580 prevBar = bar;
|
Chris@2
|
581 }
|
Chris@2
|
582 WormEvent ev = new WormEvent(time, time, time, pitch, vol,
|
Chris@2
|
583 ++beats,1.0,flags, ShortMessage.NOTE_ON, ch, track);
|
Chris@2
|
584 ev.label = label;
|
Chris@2
|
585 list.add(ev);
|
Chris@2
|
586 // System.out.println(time + " " + label);
|
Chris@2
|
587 }
|
Chris@2
|
588 s.set(inputFile.readLine());
|
Chris@2
|
589 }
|
Chris@2
|
590 return list;
|
Chris@2
|
591 } // readLabelFile()
|
Chris@2
|
592
|
Chris@2
|
593 public void writeLabelFile(String fileName) throws Exception {
|
Chris@2
|
594 PrintStream out = new PrintStream(new File(fileName));
|
Chris@2
|
595 out.printf("###Created automatically\n");
|
Chris@2
|
596 for (Event ev : l)
|
Chris@2
|
597 out.printf("%5.3f\t%s\n", ev.keyDown, ((WormEvent)ev).label);
|
Chris@2
|
598 out.close();
|
Chris@2
|
599 } // writeLabelFile()
|
Chris@2
|
600
|
Chris@2
|
601 public static EventList readWormFile(String fileName) throws Exception {
|
Chris@2
|
602 EventList list = new EventList();
|
Chris@2
|
603 BufferedReader inputFile = new BufferedReader(new FileReader(fileName));
|
Chris@2
|
604 Matcher s = new Matcher(inputFile.readLine());
|
Chris@2
|
605 int lineCount = 1;
|
Chris@2
|
606 if (!s.matchString("WORM Version:"))
|
Chris@2
|
607 throw new WormFileParseException("WORM format: header not found");
|
Chris@2
|
608 if (s.getDouble() < 1.01)
|
Chris@2
|
609 throw new WormFileParseException("WORM format: v1.0 not supported");
|
Chris@2
|
610 int dataCountDown = -1;
|
Chris@2
|
611 int beat = 0;
|
Chris@2
|
612 while (true) {
|
Chris@2
|
613 s.set(inputFile.readLine());
|
Chris@2
|
614 lineCount++;
|
Chris@2
|
615 if (dataCountDown == 0) {
|
Chris@2
|
616 if (s.hasData())
|
Chris@2
|
617 System.err.println("Ignoring trailing data past line " +
|
Chris@2
|
618 lineCount);
|
Chris@2
|
619 return list;
|
Chris@2
|
620 } else if (!s.hasData())
|
Chris@2
|
621 throw new WormFileParseException("Unexpected EOF");
|
Chris@2
|
622 if (dataCountDown < 0) {
|
Chris@2
|
623 if (s.matchString("Length:"))
|
Chris@2
|
624 dataCountDown = s.getInt();
|
Chris@2
|
625 } else {
|
Chris@2
|
626 double time = s.getDouble();
|
Chris@2
|
627 double tempo = s.getDouble();
|
Chris@2
|
628 double loudness = s.getDouble();
|
Chris@2
|
629 int flags = s.getInt();
|
Chris@2
|
630 if ((flags & WormFile.TRACK) != 0)
|
Chris@2
|
631 beat++; // i.e. always, as index for comparing files
|
Chris@2
|
632 list.add(new WormEvent(time, tempo, loudness, beat, flags));
|
Chris@2
|
633 dataCountDown--;
|
Chris@2
|
634 }
|
Chris@2
|
635 }
|
Chris@2
|
636 } // readWormFile()
|
Chris@2
|
637
|
Chris@2
|
638 public static String getAudioFileFromWormFile(String wormFile) {
|
Chris@2
|
639 return getWormFileAttribute(wormFile, "AudioFile");
|
Chris@2
|
640 } // getAudioFileFromWormFile()
|
Chris@2
|
641
|
Chris@2
|
642 public static double getTrackLevelFromWormFile(String wormFile) {
|
Chris@2
|
643 String level = getWormFileAttribute(wormFile,WormParameters.TRACKLEVEL);
|
Chris@2
|
644 try {
|
Chris@2
|
645 int i = level.indexOf("/");
|
Chris@2
|
646 if (i >= 0)
|
Chris@2
|
647 return Double.parseDouble(level.substring(0,i)) /
|
Chris@2
|
648 Double.parseDouble(level.substring(i+1));
|
Chris@2
|
649 else
|
Chris@2
|
650 return Double.parseDouble(level);
|
Chris@2
|
651 } catch (Exception e) {
|
Chris@2
|
652 System.err.println("Error getting TrackLevel:\n" + e);
|
Chris@2
|
653 return 1;
|
Chris@2
|
654 }
|
Chris@2
|
655 } // getTrackLevelFromWormFile()
|
Chris@2
|
656
|
Chris@2
|
657 public static String getWormFileAttribute(String wormFile, String attr) {
|
Chris@2
|
658 try {
|
Chris@2
|
659 BufferedReader r = new BufferedReader(new FileReader(wormFile));
|
Chris@2
|
660 String line = r.readLine();
|
Chris@2
|
661 attr += ":";
|
Chris@2
|
662 while (line != null) {
|
Chris@2
|
663 if (line.startsWith(attr))
|
Chris@2
|
664 return line.substring(attr.length()).trim();
|
Chris@2
|
665 line = r.readLine();
|
Chris@2
|
666 }
|
Chris@2
|
667 } catch (Exception e) {
|
Chris@2
|
668 System.err.println(e);
|
Chris@2
|
669 }
|
Chris@2
|
670 return null;
|
Chris@2
|
671 } // getWormFileAttribute()
|
Chris@2
|
672
|
Chris@2
|
673 public static EventList readMatchFile(String fileName) throws Exception {
|
Chris@2
|
674 EventList list = new EventList();
|
Chris@2
|
675 boolean startNote = timingCorrection;
|
Chris@2
|
676 int eventFlags, numerator, denominator;
|
Chris@2
|
677 String element;
|
Chris@2
|
678 BufferedReader inputFile = new BufferedReader(new FileReader(fileName));
|
Chris@2
|
679 double versionNumber = 1.0;
|
Chris@2
|
680 double onset, offset, eOffset, beat, duration;
|
Chris@2
|
681 int velocity, pitch, octave;
|
Chris@2
|
682 int lineCount = 1;
|
Chris@2
|
683 Matcher s = new Matcher(inputFile.readLine());
|
Chris@2
|
684 while (s.hasData()) {
|
Chris@2
|
685 eventFlags = 0;
|
Chris@2
|
686 beat = UNKNOWN;
|
Chris@2
|
687 duration = UNKNOWN;
|
Chris@2
|
688 // System.out.println("Processing line " + lineCount);
|
Chris@2
|
689 if (s.matchString("info(")) { // meta-data
|
Chris@2
|
690 if (s.matchString("timeSignature,")) {
|
Chris@2
|
691 numerator = s.getInt();
|
Chris@2
|
692 // ss1 << "beatsPerBar=" << numerator << ends;
|
Chris@2
|
693 s.skip('/');
|
Chris@2
|
694 denominator = s.getInt();
|
Chris@2
|
695 // ss2 << "beatUnits=" << denominator;
|
Chris@2
|
696 } else if (s.matchString("beatSubdivision,")) {
|
Chris@2
|
697 // strcpy(buf, "beatSubdivisions=");
|
Chris@2
|
698 // int i = strlen(buf);
|
Chris@2
|
699 // f.getline(buf+i, SZ-i, ']');
|
Chris@2
|
700 // strcat(buf, "]");
|
Chris@2
|
701 // parameters->add(buf);
|
Chris@2
|
702 s.skip(']');
|
Chris@2
|
703 } else if (s.matchString("matchFileVersion,")) {
|
Chris@2
|
704 versionNumber = s.getDouble();
|
Chris@2
|
705 } else if (s.matchString("midiClockUnits,")) {
|
Chris@2
|
706 clockUnits = s.getInt();
|
Chris@2
|
707 } else if (s.matchString("midiClockRate,")) {
|
Chris@2
|
708 clockRate = s.getInt();
|
Chris@2
|
709 }
|
Chris@2
|
710 s.set("%"); // don't expect the second half of the Prolog term
|
Chris@2
|
711 } else if (s.matchString("snote(")) {
|
Chris@2
|
712 s.skip(','); // identifier
|
Chris@2
|
713 s.skip(']'); // note name
|
Chris@2
|
714 s.skip(','); // ',' after note name
|
Chris@2
|
715 s.skip(','); // octave
|
Chris@2
|
716 s.skip(','); // onset time (in beats, integer part, bar:beat)
|
Chris@2
|
717 boolean isBt = s.matchString("0");
|
Chris@2
|
718 s.skip(','); // onset time (in beats, fractional part)
|
Chris@2
|
719 s.skip(','); // duration (in beats, fraction)
|
Chris@2
|
720 try {
|
Chris@2
|
721 beat = s.getDouble();
|
Chris@2
|
722 } catch (NumberFormatException e) {
|
Chris@2
|
723 System.err.println("Bad beat number on line " + lineCount);
|
Chris@2
|
724 beat = UNKNOWN;
|
Chris@2
|
725 }
|
Chris@2
|
726 if ((beat == Math.rint(beat)) != isBt)
|
Chris@2
|
727 System.err.println("Inconsistent beats on line "+lineCount);
|
Chris@2
|
728 s.skip(','); // onset time (in beats, decimal)
|
Chris@2
|
729 try {
|
Chris@2
|
730 duration = s.getDouble() - beat;
|
Chris@2
|
731 } catch (NumberFormatException e) {
|
Chris@2
|
732 System.err.println("Bad duration on line " + lineCount);
|
Chris@2
|
733 duration = UNKNOWN;
|
Chris@2
|
734 }
|
Chris@2
|
735 s.skip(','); // offset time (in beats, decimal)
|
Chris@2
|
736 s.skip('['); // additional info (e.g. melody/arpeggio/grace)
|
Chris@2
|
737 do {
|
Chris@2
|
738 element = s.getString();
|
Chris@2
|
739 eventFlags |= flags.getFlag(element);
|
Chris@2
|
740 } while (s.matchString(","));
|
Chris@2
|
741 s.skip('-');
|
Chris@2
|
742 } else if (s.matchString("trill(")) {
|
Chris@2
|
743 eventFlags |= flags.getFlag("trill");
|
Chris@2
|
744 s.skip('-');
|
Chris@2
|
745 } else if (s.matchString("ornament(")) {
|
Chris@2
|
746 eventFlags |= flags.getFlag("ornament");
|
Chris@2
|
747 s.skip('-');
|
Chris@2
|
748 } else if (s.matchString("trailing_played_note-") ||
|
Chris@2
|
749 s.matchString("hammer_bounce-") ||
|
Chris@2
|
750 s.matchString("no_score_note-") ||
|
Chris@2
|
751 s.matchString("insertion-")) {
|
Chris@2
|
752 eventFlags |= flags.getFlag("unscored");
|
Chris@2
|
753 } else if (!s.matchString("%")) { // Prolog comment
|
Chris@2
|
754 throw new MatchFileParseException("error 4; line "+lineCount);
|
Chris@2
|
755 }
|
Chris@2
|
756 // READ 2nd term of Prolog expression
|
Chris@2
|
757 if (s.matchString("note(")) {
|
Chris@2
|
758 s.skip('['); // skip identifier
|
Chris@2
|
759 String note = s.getString();
|
Chris@2
|
760 switch(Character.toUpperCase(note.charAt(0))) {
|
Chris@2
|
761 case 'A': pitch = 9; break;
|
Chris@2
|
762 case 'B': pitch = 11; break;
|
Chris@2
|
763 case 'C': pitch = 0; break;
|
Chris@2
|
764 case 'D': pitch = 2; break;
|
Chris@2
|
765 case 'E': pitch = 4; break;
|
Chris@2
|
766 case 'F': pitch = 5; break;
|
Chris@2
|
767 case 'G': pitch = 7; break;
|
Chris@2
|
768 default: throw new MatchFileParseException(
|
Chris@2
|
769 "Bad note on line " + lineCount);
|
Chris@2
|
770 }
|
Chris@2
|
771 s.skip(',');
|
Chris@2
|
772 String mod = s.getString();
|
Chris@2
|
773 for (int i = 0; i < mod.length(); i++) {
|
Chris@2
|
774 switch (mod.charAt(i)) {
|
Chris@2
|
775 case '#': pitch++; break;
|
Chris@2
|
776 case 'b': pitch--; break;
|
Chris@2
|
777 case 'n': break;
|
Chris@2
|
778 default: throw new MatchFileParseException("error 5 " +
|
Chris@2
|
779 lineCount);
|
Chris@2
|
780 }
|
Chris@2
|
781 }
|
Chris@2
|
782 s.skip(',');
|
Chris@2
|
783 octave = s.getInt();
|
Chris@2
|
784 pitch += 12 * octave;
|
Chris@2
|
785 s.skip(',');
|
Chris@2
|
786 onset = s.getInt();
|
Chris@2
|
787 s.skip(',');
|
Chris@2
|
788 offset = s.getInt();
|
Chris@2
|
789 if (versionNumber > 1.0) {
|
Chris@2
|
790 s.skip(',');
|
Chris@2
|
791 eOffset = s.getInt();
|
Chris@2
|
792 } else
|
Chris@2
|
793 eOffset = offset;
|
Chris@2
|
794 s.skip(',');
|
Chris@2
|
795 velocity = s.getInt();
|
Chris@2
|
796 onset /= clockUnits * 1000000.0 / clockRate;
|
Chris@2
|
797 offset /= clockUnits * 1000000.0 / clockRate;
|
Chris@2
|
798 eOffset /= clockUnits * 1000000.0 / clockRate;
|
Chris@2
|
799 if (timingCorrection) {
|
Chris@2
|
800 if (startNote) {
|
Chris@2
|
801 timingDisplacement = onset - timingDisplacement;
|
Chris@2
|
802 startNote = false;
|
Chris@2
|
803 }
|
Chris@2
|
804 onset -= timingDisplacement;
|
Chris@2
|
805 offset -= timingDisplacement;
|
Chris@2
|
806 eOffset -= timingDisplacement;
|
Chris@2
|
807 }
|
Chris@2
|
808 int m = flags.getFlag("s");
|
Chris@2
|
809 if ((((eventFlags & m) != 0) && !noMelody) ||
|
Chris@2
|
810 (((eventFlags & m) == 0) && !onlyMelody)) {
|
Chris@2
|
811 Event e = new Event(onset, offset, eOffset, pitch, velocity,
|
Chris@2
|
812 beat, duration, eventFlags);
|
Chris@2
|
813 list.add(e);
|
Chris@2
|
814 }
|
Chris@2
|
815 } else if (!s.matchString("no_played_note.") &&
|
Chris@2
|
816 !s.matchString("trailing_score_note.") &&
|
Chris@2
|
817 !s.matchString("deletion.") &&
|
Chris@2
|
818 !s.matchString("%"))
|
Chris@2
|
819 throw new MatchFileParseException("error 6; line " + lineCount);
|
Chris@2
|
820 s.set(inputFile.readLine());
|
Chris@2
|
821 lineCount++;
|
Chris@2
|
822 }
|
Chris@2
|
823 return list;
|
Chris@2
|
824 } // readMatchFile()
|
Chris@2
|
825
|
Chris@2
|
826 public static void main(String[] args) throws Exception { // quick test
|
Chris@2
|
827 //System.out.println("Test");
|
Chris@2
|
828 //readLabelFile(args[0]).writeLabelFile("tmp.txt");
|
Chris@2
|
829 readLabelFile(args[0]).print();
|
Chris@2
|
830 System.exit(0);
|
Chris@2
|
831 EventList el = readMatchFile(args[0]);
|
Chris@2
|
832 WormFile wf = new WormFile(null, el);
|
Chris@2
|
833 if (args.length >= 2) {
|
Chris@2
|
834 double sm = Double.parseDouble(args[1]);
|
Chris@2
|
835 wf.smooth(Worm.FULL_GAUSS, sm, sm, 0);
|
Chris@2
|
836 } else
|
Chris@2
|
837 wf.smooth(Worm.NONE, 0, 0, 0);
|
Chris@2
|
838 wf.write("worm.out");
|
Chris@2
|
839 if (args.length == 3)
|
Chris@2
|
840 el.print();
|
Chris@2
|
841 } // main()
|
Chris@2
|
842
|
Chris@2
|
843 } // class EventList
|