private static long editPosition;
private static boolean makeGUI = true, initSound = true, edited = false, drawEmptyTracks = false;
public static final int DEFAULT_RESOLUTION = 96, DEFAULT_TRACKS = 4;
+ public static final int WHOLE_NOTE = 0, HALF_NOTE = 1, QUARTER_NOTE = 2, EIGHTH_NOTE = 3, SIXTEENTH_NOTE = 4;
/**
* Starts the application.
// Acquires MIDI devices and connects them.
System.out.print("Initializing MIDI devices.");
try {
+ // Configures sequencer
sequencer = MidiSystem.getSequencer();
System.out.print(".");
sequencer.open();
+ sequencer.addMetaEventListener(new SongEndListener());
+
+ // Configures synthesizer
synthesizer = MidiSystem.getSynthesizer();
System.out.print(".");
synthesizer.open();
+
+ // Configures receiver, transmitter and channels.
receiver = synthesizer.getReceiver();
sequencer.getTransmitter().setReceiver(receiver);
channels = synthesizer.getChannels();
}
System.out.println("Done");
+ // Loads user preferences (work directory, last opened files etc).
+ loadPreferences();
+
//If a filename is given as the command-line argument, attempts to load a sequence from the file.
if (fileArg != null) {
System.out.print("Loading MIDI sequence from " + fileArg + "...");
* Calculates the position (measures, beats, ticks) in the current sequence for the given tick position.
* @return an array of integers where index 0 is measures, 1 is beats and 2 is ticks.
*/
- public static int[] getPositionForTick(long ticks) {
+ public static int[] getPositionForTicks(long ticks) {
/*
int measures, beats, ticks;
for (int i = 0; i < timeSignatures.length; i++) {
/**
* Wraps each NoteOn event in the track with its NoteOff event in a MooNote.
+ * @param track the track to convert
+ * @param quantize whether to round locations and durations in the track to nearest 16th
+ * @return a list of the created MooNotes
*/
- public static void convertTrack(Track track) {
+ public static List convertTrack(Track track, boolean quantize) {
// Searches the track for NoteOn and NoteOff events
ArrayList noteOns = new ArrayList(track.size() / 2);
ArrayList noteOffs = new ArrayList(track.size() / 2);
+ ArrayList newMooNotes = new ArrayList();
MidiEvent event;
for (int j = 0; j < track.size(); j++) {
event = track.get(j);
ShortMessage onMsg, nextOffMsg;
while(iOn.hasNext()) {
on = (MidiEvent)iOn.next();
- onMsg = (ShortMessage)on.getMessage();
- iOff = noteOffs.iterator();
- while(iOff.hasNext()) {
- nextOff = (MidiEvent)iOff.next();
- nextOffMsg = (ShortMessage)nextOff.getMessage();
- if(onMsg.getChannel() == nextOffMsg.getChannel() &&
- onMsg.getData1() == nextOffMsg.getData1() &&
- c.compare(nextOff, on) > 0) {
- off = nextOff;
- iOff.remove();
- break;
+ if (!(on instanceof MooNote)) {
+ onMsg = (ShortMessage)on.getMessage();
+ iOff = noteOffs.iterator();
+ while(iOff.hasNext()) {
+ nextOff = (MidiEvent)iOff.next();
+ nextOffMsg = (ShortMessage)nextOff.getMessage();
+ if(onMsg.getChannel() == nextOffMsg.getChannel() &&
+ onMsg.getData1() == nextOffMsg.getData1() &&
+ c.compare(nextOff, on) > 0) {
+ off = nextOff;
+ iOff.remove();
+ break;
+ }
+
}
-
- }
- track.remove(on);
- if (off != null) {
- track.add(new MooNote(on, off));
- } else {
- track.add(new MooNote(on, new MidiEvent((ShortMessage)on.getMessage().clone(), on.getTick() + 48)));
+ track.remove(on);
+ MooNote mn;
+ if (off != null) {
+ mn = new MooNote(on, off);
+ } else {
+ mn = new MooNote(on, new MidiEvent((ShortMessage)on.getMessage().clone(), on.getTick() + 48));
+ }
+ track.add(mn);
+ newMooNotes.add(mn);
+ iOn.remove();
}
- iOn.remove();
}
+ if (quantize) quantize(newMooNotes, SIXTEENTH_NOTE, true, true);
+ return newMooNotes;
}
/**
public static boolean load(String file) {
// Loads sequence from file
filename = file;
- try {
- seq = MidiSystem.getSequence(new File(filename));
- } catch (InvalidMidiDataException e) {
- return false;
- } catch (IOException e) {
- return false;
- }
+ try {seq = MidiSystem.getSequence(new File(filename));}
+ catch (Exception e) {return false;}
edited = false;
Track[] tracks = seq.getTracks();
// Converts tracks.
for (int i = 0; i < tracks.length; i++) {
- convertTrack(tracks[i]);
+ convertTrack(tracks[i], false);
}
// Sends sequence to GUI and sequencer, then returns
return true;
}
+ /**
+ * Quantizes the given list of MIDI events
+ * @param notes a list of the notes to quantize
+ * @param resolution the note size to round each note to
+ * @param location whether the quantize should affect the location of the note
+ * @param duration whether the quantize should affect the duration of the note
+ */
+ public static void quantize(List notes, int resolution, boolean location, boolean duration) {
+ // Math.round(mn.getTick() / ticksPerSixteenth);
+ }
+
+ /**
+ * Loads the user preferences.
+ */
+ public static void loadPreferences() {
+
+ }
+
+ /**
+ * Saves the user preferences.
+ */
+ public static void savePreferences() {
+
+ }
+
/**
* Prompts the user .
*/
if (gui != null) {
if (promptOnUnsavedChanges()) return;
}
+ savePreferences();
if (sequencer.isOpen()) sequencer.close();
if (synthesizer.isOpen()) synthesizer.close();
System.exit(0);
}
/**
- * A Comparator for sorting lists of MidiEvents.
+ * A Ccmparator for sorting lists of MidiEvents.
*/
public static class MidiEventComparator implements Comparator {
public int compare(Object o1, Object o2) {
return (int)(((MidiEvent)o1).getTick() - ((MidiEvent)o2).getTick());
}
}
+
+ /**
+ * A listener for detecting the end of the sequence.
+ */
+ public static void class SongEndListener implements MetaEventListener {
+ public void meta(MetaMessage event) {
+ if (event.getType() == 47 ) sequencer.stop(); // End of stream
+ }
+ }
}