/* Copyright (C) 2001, 2006 by Simon Dixon This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (the file gpl.txt); if not, download it from http://www.gnu.org/licenses/gpl.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package at.ofai.music.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiEvent; import javax.sound.midi.MidiMessage; import javax.sound.midi.MidiSystem; import javax.sound.midi.Sequence; import javax.sound.midi.ShortMessage; import javax.sound.midi.Track; // Adapted from eventList::readMatchFile in beatroot/src/eventMidi.cpp // Reads in a Prolog score+performance (.match) file; returns it as an eventList // Lines in the match file can be of the form: // hammer_bounce-PlayedNote. // info(Attribute, Value). // insertion-PlayedNote. // ornament(Anchor)-PlayedNote. // ScoreNote-deletion. // ScoreNote-PlayedNote. // ScoreNote-trailing_score_note. // trailing_played_note-PlayedNote. // trill(Anchor)-PlayedNote. // where ScoreNote is of the form // snote(Anchor,[NoteName,Modifier],Octave,Bar:Beat,Offset,Duration, // BeatNumber,DurationInBeats,ScoreAttributesList) // e.g. snote(n1,[b,b],5,1:1,0,3/16,0,0.75,[s]) // and PlayedNote is of the form // note(Number,[NoteName,Modifier],Octave,Onset,Offset,AdjOffset,Velocity) // e.g. note(1,[a,#],5,5054,6362,6768,53) class WormFileParseException extends RuntimeException { static final long serialVersionUID = 0; public WormFileParseException(String s) { super(s); } // constructor } // class WormFileParseException class MatchFileParseException extends RuntimeException { static final long serialVersionUID = 0; public MatchFileParseException(String s) { super(s); } // constructor } // class MatchFileParseException class BTFileParseException extends RuntimeException { static final long serialVersionUID = 0; public BTFileParseException(String s) { super(s); } // constructor } // class BTFileParseException // Process the strings which label extra features of notes in match files. // We assume no more than 32 distinct labels in a file. class Flags { String[] labels = new String[32]; int size = 0; int getFlag(String s) { if ((s == null) || s.equals("")) return 0; //int val = 1; for (int i = 0; i < size; i++) if (s.equals(labels[i])) return 1 << i; if (size == 32) { System.err.println("Overflow: Too many flags: " + s); size--; } labels[size] = s; return 1 << size++; } // getFlag() String getLabel(int i) { if (i >= size) return "ERROR: Unknown flag"; return labels[i]; } // getLabel() } // class Flags // A score/match/midi file is represented as an EventList object, // which contains pointers to the head and tail links, and some // class-wide parameters. Parameters are class-wide, as it is // assumed that the Worm has only one input file at a time. public class EventList implements Serializable { private static final long serialVersionUID = 1L; public LinkedList<Event> l; protected static boolean timingCorrection = false; protected static double timingDisplacement = 0; protected static int clockUnits = 480; protected static int clockRate = 500000; protected static double metricalLevel = 0; public static final double UNKNOWN = Double.NaN; protected static boolean noMelody = false; protected static boolean onlyMelody = false; protected static Flags flags = new Flags(); public EventList() { l = new LinkedList<Event>(); } // constructor public EventList(EventList e) { this(); ListIterator<Event> it = e.listIterator(); while (it.hasNext()) add(it.next()); } // constructor public EventList(Event[] e) { this(); for (int i=0; i < e.length; i++) add(e[i]); } // constructor public void add(Event e) { l.add(e); } // add() public void add(EventList ev) { l.addAll(ev.l); } // add() public void insert(Event newEvent, boolean uniqueTimes) { ListIterator<Event> li = l.listIterator(); while (li.hasNext()) { int sgn = newEvent.compareTo(li.next()); if (sgn < 0) { li.previous(); break; } else if (uniqueTimes && (sgn == 0)) { li.remove(); break; } } li.add(newEvent); } // insert() public ListIterator<Event> listIterator() { return l.listIterator(); } // listIterator() public Iterator<Event> iterator() { return l.iterator(); } // iterator() public int size() { return l.size(); } // size() public Event[] toArray() { return toArray(0); } // toArray() public double[] toOnsetArray() { double[] d = new double[l.size()]; int i = 0; for (Iterator<Event> it = l.iterator(); it.hasNext(); i++) d[i] = it.next().keyDown; return d; } // toOnsetArray() public Event[] toArray(int match) { int count = 0; for (Event e : l) if ((match == 0) || (e.midiCommand == match)) count++; Event[] a = new Event[count]; int i = 0; for (Event e : l) if ((match == 0) || (e.midiCommand == match)) a[i++] = e; return a; } // toArray() public void writeBinary(String fileName) { try { ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(fileName)); oos.writeObject(this); oos.close(); } catch (IOException e) { System.err.println(e); } } // writeBinary() public static EventList readBinary(String fileName) { try { ObjectInputStream ois = new ObjectInputStream( new FileInputStream(fileName)); EventList e = (EventList) ois.readObject(); ois.close(); return e; } catch (IOException e) { System.err.println(e); return null; } catch (ClassNotFoundException e) { System.err.println(e); return null; } } // readBinary() public void writeMIDI(String fileName) { writeMIDI(fileName, null); } // writeMIDI() public void writeMIDI(String fileName, EventList pedal) { try { MidiSystem.write(toMIDI(pedal), 1, new File(fileName)); } catch (Exception e) { System.err.println("Error: Unable to write MIDI file " + fileName); e.printStackTrace(); } } // writeMIDI() public Sequence toMIDI(EventList pedal) throws InvalidMidiDataException { final int midiTempo = 1000000; Sequence s = new Sequence(Sequence.PPQ, 1000); Track[] tr = new Track[16]; tr[0] = s.createTrack(); MetaMessage mm = new MetaMessage(); byte[] b = new byte[3]; b[0] = (byte)((midiTempo >> 16) & 0xFF); b[1] = (byte)((midiTempo >> 8) & 0xFF); b[2] = (byte)(midiTempo & 0xFF); mm.setMessage(0x51, b, 3); tr[0].add(new MidiEvent(mm, 0L)); for (Event e : l) { // from match or beatTrack file if (e.midiCommand == 0) // skip beatTrack file break; if (tr[e.midiTrack] == null) tr[e.midiTrack] = s.createTrack(); //switch (e.midiCommand) //case ShortMessage.NOTE_ON: //case ShortMessage.POLY_PRESSURE: //case ShortMessage.CONTROL_CHANGE: //case ShortMessage.PROGRAM_CHANGE: //case ShortMessage.CHANNEL_PRESSURE: //case ShortMessage.PITCH_BEND: ShortMessage sm = new ShortMessage(); sm.setMessage(e.midiCommand, e.midiChannel, e.midiPitch, e.midiVelocity); tr[e.midiTrack].add(new MidiEvent(sm, (long)Math.round(1000 * e.keyDown))); if (e.midiCommand == ShortMessage.NOTE_ON) { sm = new ShortMessage(); sm.setMessage(ShortMessage.NOTE_OFF, e.midiChannel, e.midiPitch, 0); tr[e.midiTrack].add(new MidiEvent(sm, (long)Math.round(1000 * e.keyUp))); } } if (pedal != null) { // from MIDI file // if (t.size() > 0) // otherwise beatTrack files leave an empty trk // t = s.createTrack(); for (Event e : pedal.l) { if (tr[e.midiTrack] == null) tr[e.midiTrack] = s.createTrack(); ShortMessage sm = new ShortMessage(); sm.setMessage(e.midiCommand, e.midiChannel, e.midiPitch, e.midiVelocity); tr[e.midiTrack].add(new MidiEvent(sm, (long)Math.round(1000 * e.keyDown))); if (e.midiCommand == ShortMessage.NOTE_ON) { sm = new ShortMessage(); sm.setMessage(ShortMessage.NOTE_OFF, e.midiChannel, e.midiPitch,e.midiVelocity); tr[e.midiTrack].add(new MidiEvent(sm, (long)Math.round(1000 * e.keyUp))); } //catch (InvalidMidiDataException exception) {} } } return s; } // toMIDI() public static EventList readMidiFile(String fileName) { return readMidiFile(fileName, 0); } // readMidiFile() public static EventList readMidiFile(String fileName, int skipTrackFlag) { EventList list = new EventList(); Sequence s; try { s = MidiSystem.getSequence(new File(fileName)); } catch (Exception e) { e.printStackTrace(); return list; } double midiTempo = 500000; double tempoFactor = midiTempo / s.getResolution() / 1000000.0; // System.err.println(tempoFactor); Event[][] noteOns = new Event[128][16]; Track[] tracks = s.getTracks(); for (int t = 0; t < tracks.length; t++, skipTrackFlag >>= 1) { if ((skipTrackFlag & 1) == 1) continue; for (int e = 0; e < tracks[t].size(); e++) { MidiEvent me = tracks[t].get(e); MidiMessage mm = me.getMessage(); double time = me.getTick() * tempoFactor; byte[] mesg = mm.getMessage(); int channel = mesg[0] & 0x0F; int command = mesg[0] & 0xF0; if (command == ShortMessage.NOTE_ON) { int pitch = mesg[1] & 0x7F; int velocity = mesg[2] & 0x7F; if (noteOns[pitch][channel] != null) { if (velocity == 0) { // NOTE_OFF in disguise :( noteOns[pitch][channel].keyUp = time; noteOns[pitch][channel].pedalUp = time; noteOns[pitch][channel] = null; } else System.err.println("Double note on: n=" + pitch + " c=" + channel + " t1=" + noteOns[pitch][channel] + " t2=" + time); } else { Event n = new Event(time, 0, 0, pitch, velocity, -1, -1, 0, ShortMessage.NOTE_ON, channel, t); noteOns[pitch][channel] = n; list.add(n); } } else if (command == ShortMessage.NOTE_OFF) { int pitch = mesg[1] & 0x7F; noteOns[pitch][channel].keyUp = time; noteOns[pitch][channel].pedalUp = time; noteOns[pitch][channel] = null; } else if (command == 0xF0) { if ((channel == 0x0F) && (mesg[1] == 0x51)) { midiTempo = (mesg[5] & 0xFF) | ((mesg[4] & 0xFF) << 8) | ((mesg[3] & 0xFF) << 16); tempoFactor = midiTempo / s.getResolution() / 1000000.0; // System.err.println("Info: Tempo change: " + midiTempo + // " tf=" + tempoFactor); } } else if (mesg.length > 3) { System.err.println("midi message too long: " + mesg.length); System.err.println("\tFirst byte: " + mesg[0]); } else { int b0 = mesg[0] & 0xFF; int b1 = -1; int b2 = -1; if (mesg.length > 1) b1 = mesg[1] & 0xFF; if (mesg.length > 2) b2 = mesg[2] & 0xFF; list.add(new Event(time, time, -1, b1, b2, -1, -1, 0, b0 & 0xF0, b0 & 0x0F, t)); } } } for (int pitch = 0; pitch < 128; pitch++) for (int channel = 0; channel < 16; channel++) if (noteOns[pitch][channel] != null) System.err.println("Missing note off: n=" + noteOns[pitch][channel].midiPitch + " t=" + noteOns[pitch][channel].keyDown); return list; } // readMidiFile() public void print() { for (Iterator<Event> i = l.iterator(); i.hasNext(); ) i.next().print(flags); } // print() public static void setTimingCorrection(double corr) { timingCorrection = corr >= 0; timingDisplacement = corr; } // setTimingCorrection() // public static EventList readBeatsAsText(String fileName) throws Exception { // EventList list = new EventList(); // BufferedReader inputFile = new BufferedReader(new FileReader(fileName)); // String s = inputFile.readLine(); // if (s.startsWith("###")) // return readLabelFile(fileName); // int beats = 0; // int pitch = 56; // int vol = 80; // int ch = 10; // int track = 0; // int fl = 1; // while (s != null) { // int ind = s.indexOf(','); // if (ind < 0) // ind = s.indexOf(' '); // double time = 0; // if (ind >= 0) { // String tmp = s.substring(0,ind).trim(); // if (tmp.length() == 0) { // s = inputFile.readLine(); // continue; // } // time = Double.parseDouble(tmp); // s = s.substring(ind+1); // } else { // String tmp = s.trim(); // if (tmp.length() > 0) // time = Double.parseDouble(tmp); // s = inputFile.readLine(); // } // list.add(new Event(time, time, time, pitch, vol, ++beats, // 1.0, fl, ShortMessage.NOTE_ON, ch, track)); // } // return list; // } // readBeatsAsText() // public static EventList readBeatTrackFile(String fileName) throws Exception{ // if (!fileName.endsWith(".tmf")) // || fileName.endsWith(".csv")) // return readBeatsAsText(fileName); // else { // EventList list = new EventList(); // BufferedReader inputFile = new BufferedReader(new FileReader(fileName)); // Matcher s = new Matcher(inputFile.readLine()); // if (!s.matchString("MFile")) // throw new BTFileParseException("Header not found"); // s.getInt(); // skip fileType // int tracks = s.getInt(); // int div = s.getInt(); // int tempo = 500000; // default tempo // double tf = 1e6 / tempo * div; // int lineCount = 1; // int beats = 0; // for (int track = 0; track < tracks; track++) { // s.set(inputFile.readLine()); // lineCount++; // if (!s.matchString("MTrk")) // throw new BTFileParseException("MTrk not found"); // s.set(inputFile.readLine()); // lineCount++; // while (!s.matchString("TrkEnd")) { // double time = s.getInt() / tf; // s.trimSpace(); // if (s.matchString("Tempo")) { // tempo = s.getInt(); // tf = 1e6 / tempo * div; // } else if (s.matchString("On")) { // s.trimSpace(); // s.matchString("ch="); // int ch = s.getInt(); // s.trimSpace(); // if (!s.matchString("n=")) // s.matchString("note="); // int pitch = s.getInt(); // s.trimSpace(); // if (!s.matchString("v=")) // s.matchString("vol="); // int vol = s.getInt(); // s.set(inputFile.readLine()); // lineCount++; // s.getInt(); // s.trimSpace(); // s.matchString("Off"); // s.skip('v'); // s.matchString("ol"); // s.matchString("="); // int flags = s.getInt(); // list.add(new Event(time, time, time, pitch, vol, ++beats, // 1.0, flags, ShortMessage.NOTE_ON, ch, track)); // } else if (!s.matchString("Meta TrkEnd")) { // System.err.println("Unmatched text on line " + lineCount + // ": " + s.get()); // } // s.set(inputFile.readLine()); // lineCount++; // } // } // return list; // } // } // readBeatTrackFile() // public void writeBeatsAsText(String fileName) throws Exception { // PrintStream out = new PrintStream(new File(fileName)); // char separator = '\n'; // if (fileName.endsWith(".csv")) // separator = ','; // for (Iterator<Event> it = iterator(); it.hasNext(); ) { // Event e = it.next(); // out.printf("%5.3f%c", e.keyDown, it.hasNext()? separator: '\n'); // } // out.close(); // } // writeBeatsAsText() // public void writeBeatTrackFile(String fileName) throws Exception { // if (fileName.endsWith(".txt") || fileName.endsWith(".csv")) // writeBeatsAsText(fileName); // else { // PrintStream out = new PrintStream(new File(fileName)); // out.println("MFile 0 1 500"); // out.println("MTrk"); // out.println(" 0 Tempo 500000"); // int time = 0; // for (Iterator<Event> it = iterator(); it.hasNext(); ) { // Event e = it.next(); // time = (int) Math.round(1000 * e.keyDown); // out.printf("%6d On ch=%3d n=%3d v=%3d\n", // time, e.midiChannel, e.midiPitch, e.midiVelocity); // out.printf("%6d Off ch=%3d n=%3d v=%3d\n", // time, e.midiChannel, e.midiPitch, e.flags); // } // out.printf("%6d Meta TrkEnd\nTrkEnd\n", time); // out.close(); // } // } // writeBeatTrackFile() // /** Reads a file containing time,String pairs into an EventList. */ // public static EventList readLabelFile(String fileName) throws Exception { // EventList list = new EventList(); // BufferedReader inputFile = new BufferedReader(new FileReader(fileName)); // Matcher s = new Matcher(inputFile.readLine()); // int prevBar = 0; // int beats = 0; // int pitch = 56; // int vol = 80; // int ch = 10; // int track = 0; // while (s.hasData()) { // if (!s.matchString("#")) { // double time = s.getDouble(); // String label = s.get().trim(); // int colon = label.indexOf(':'); // int beat = 0; // if (colon < 0) // colon = label.length(); // else // beat = Integer.parseInt(label.substring(colon+1)); // int bar = Integer.parseInt(label.substring(0, colon)); // int flags = WormFile.BEAT; // if (bar != prevBar) { // flags |= WormFile.BAR; // prevBar = bar; // } // WormEvent ev = new WormEvent(time, time, time, pitch, vol, // ++beats,1.0,flags, ShortMessage.NOTE_ON, ch, track); // ev.label = label; // list.add(ev); //// System.out.println(time + " " + label); // } // s.set(inputFile.readLine()); // } // return list; // } // readLabelFile() // public void writeLabelFile(String fileName) throws Exception { // PrintStream out = new PrintStream(new File(fileName)); // out.printf("###Created automatically\n"); // for (Event ev : l) // out.printf("%5.3f\t%s\n", ev.keyDown, ((WormEvent)ev).label); // out.close(); // } // writeLabelFile() // public static EventList readWormFile(String fileName) throws Exception { // EventList list = new EventList(); // BufferedReader inputFile = new BufferedReader(new FileReader(fileName)); // Matcher s = new Matcher(inputFile.readLine()); // int lineCount = 1; // if (!s.matchString("WORM Version:")) // throw new WormFileParseException("WORM format: header not found"); // if (s.getDouble() < 1.01) // throw new WormFileParseException("WORM format: v1.0 not supported"); // int dataCountDown = -1; // int beat = 0; // while (true) { // s.set(inputFile.readLine()); // lineCount++; // if (dataCountDown == 0) { // if (s.hasData()) // System.err.println("Ignoring trailing data past line " + // lineCount); // return list; // } else if (!s.hasData()) // throw new WormFileParseException("Unexpected EOF"); // if (dataCountDown < 0) { // if (s.matchString("Length:")) // dataCountDown = s.getInt(); // } else { // double time = s.getDouble(); // double tempo = s.getDouble(); // double loudness = s.getDouble(); // int flags = s.getInt(); // if ((flags & WormFile.TRACK) != 0) // beat++; // i.e. always, as index for comparing files // list.add(new WormEvent(time, tempo, loudness, beat, flags)); // dataCountDown--; // } // } // } // readWormFile() // public static String getAudioFileFromWormFile(String wormFile) { // return getWormFileAttribute(wormFile, "AudioFile"); // } // getAudioFileFromWormFile() // public static double getTrackLevelFromWormFile(String wormFile) { // String level = getWormFileAttribute(wormFile,WormParameters.TRACKLEVEL); // try { // int i = level.indexOf("/"); // if (i >= 0) // return Double.parseDouble(level.substring(0,i)) / // Double.parseDouble(level.substring(i+1)); // else // return Double.parseDouble(level); // } catch (Exception e) { // System.err.println("Error getting TrackLevel:\n" + e); // return 1; // } // } // getTrackLevelFromWormFile() // public static String getWormFileAttribute(String wormFile, String attr) { // try { // BufferedReader r = new BufferedReader(new FileReader(wormFile)); // String line = r.readLine(); // attr += ":"; // while (line != null) { // if (line.startsWith(attr)) // return line.substring(attr.length()).trim(); // line = r.readLine(); // } // } catch (Exception e) { // System.err.println(e); // } // return null; // } // getWormFileAttribute() // public static EventList readMatchFile(String fileName) throws Exception { // EventList list = new EventList(); // boolean startNote = timingCorrection; // int eventFlags, numerator, denominator; // String element; // BufferedReader inputFile = new BufferedReader(new FileReader(fileName)); // double versionNumber = 1.0; // double onset, offset, eOffset, beat, duration; // int velocity, pitch, octave; // int lineCount = 1; // Matcher s = new Matcher(inputFile.readLine()); // while (s.hasData()) { // eventFlags = 0; // beat = UNKNOWN; // duration = UNKNOWN; // // System.out.println("Processing line " + lineCount); // if (s.matchString("info(")) { // meta-data // if (s.matchString("timeSignature,")) { // numerator = s.getInt(); // // ss1 << "beatsPerBar=" << numerator << ends; // s.skip('/'); // denominator = s.getInt(); // // ss2 << "beatUnits=" << denominator; // } else if (s.matchString("beatSubdivision,")) { // // strcpy(buf, "beatSubdivisions="); // // int i = strlen(buf); // // f.getline(buf+i, SZ-i, ']'); // // strcat(buf, "]"); // // parameters->add(buf); // s.skip(']'); // } else if (s.matchString("matchFileVersion,")) { // versionNumber = s.getDouble(); // } else if (s.matchString("midiClockUnits,")) { // clockUnits = s.getInt(); // } else if (s.matchString("midiClockRate,")) { // clockRate = s.getInt(); // } // s.set("%"); // don't expect the second half of the Prolog term // } else if (s.matchString("snote(")) { // s.skip(','); // identifier // s.skip(']'); // note name // s.skip(','); // ',' after note name // s.skip(','); // octave // s.skip(','); // onset time (in beats, integer part, bar:beat) // boolean isBt = s.matchString("0"); // s.skip(','); // onset time (in beats, fractional part) // s.skip(','); // duration (in beats, fraction) // try { // beat = s.getDouble(); // } catch (NumberFormatException e) { // System.err.println("Bad beat number on line " + lineCount); // beat = UNKNOWN; // } // if ((beat == Math.rint(beat)) != isBt) // System.err.println("Inconsistent beats on line "+lineCount); // s.skip(','); // onset time (in beats, decimal) // try { // duration = s.getDouble() - beat; // } catch (NumberFormatException e) { // System.err.println("Bad duration on line " + lineCount); // duration = UNKNOWN; // } // s.skip(','); // offset time (in beats, decimal) // s.skip('['); // additional info (e.g. melody/arpeggio/grace) // do { // element = s.getString(); // eventFlags |= flags.getFlag(element); // } while (s.matchString(",")); // s.skip('-'); // } else if (s.matchString("trill(")) { // eventFlags |= flags.getFlag("trill"); // s.skip('-'); // } else if (s.matchString("ornament(")) { // eventFlags |= flags.getFlag("ornament"); // s.skip('-'); // } else if (s.matchString("trailing_played_note-") || // s.matchString("hammer_bounce-") || // s.matchString("no_score_note-") || // s.matchString("insertion-")) { // eventFlags |= flags.getFlag("unscored"); // } else if (!s.matchString("%")) { // Prolog comment // throw new MatchFileParseException("error 4; line "+lineCount); // } // // READ 2nd term of Prolog expression // if (s.matchString("note(")) { // s.skip('['); // skip identifier // String note = s.getString(); // switch(Character.toUpperCase(note.charAt(0))) { // case 'A': pitch = 9; break; // case 'B': pitch = 11; break; // case 'C': pitch = 0; break; // case 'D': pitch = 2; break; // case 'E': pitch = 4; break; // case 'F': pitch = 5; break; // case 'G': pitch = 7; break; // default: throw new MatchFileParseException( // "Bad note on line " + lineCount); // } // s.skip(','); // String mod = s.getString(); // for (int i = 0; i < mod.length(); i++) { // switch (mod.charAt(i)) { // case '#': pitch++; break; // case 'b': pitch--; break; // case 'n': break; // default: throw new MatchFileParseException("error 5 " + // lineCount); // } // } // s.skip(','); // octave = s.getInt(); // pitch += 12 * octave; // s.skip(','); // onset = s.getInt(); // s.skip(','); // offset = s.getInt(); // if (versionNumber > 1.0) { // s.skip(','); // eOffset = s.getInt(); // } else // eOffset = offset; // s.skip(','); // velocity = s.getInt(); // onset /= clockUnits * 1000000.0 / clockRate; // offset /= clockUnits * 1000000.0 / clockRate; // eOffset /= clockUnits * 1000000.0 / clockRate; // if (timingCorrection) { // if (startNote) { // timingDisplacement = onset - timingDisplacement; // startNote = false; // } // onset -= timingDisplacement; // offset -= timingDisplacement; // eOffset -= timingDisplacement; // } // int m = flags.getFlag("s"); // if ((((eventFlags & m) != 0) && !noMelody) || // (((eventFlags & m) == 0) && !onlyMelody)) { // Event e = new Event(onset, offset, eOffset, pitch, velocity, // beat, duration, eventFlags); // list.add(e); // } // } else if (!s.matchString("no_played_note.") && // !s.matchString("trailing_score_note.") && // !s.matchString("deletion.") && // !s.matchString("%")) // throw new MatchFileParseException("error 6; line " + lineCount); // s.set(inputFile.readLine()); // lineCount++; // } // return list; // } // readMatchFile() // public static void main(String[] args) throws Exception { // quick test // //System.out.println("Test"); // //readLabelFile(args[0]).writeLabelFile("tmp.txt"); // readLabelFile(args[0]).print(); // System.exit(0); // EventList el = readMatchFile(args[0]); // WormFile wf = new WormFile(null, el); // if (args.length >= 2) { // double sm = Double.parseDouble(args[1]); // wf.smooth(Worm.FULL_GAUSS, sm, sm, 0); // } else // wf.smooth(Worm.NONE, 0, 0, 0); // wf.write("worm.out"); // if (args.length == 3) // el.print(); // } // main() } // class EventList