* Functional representation of a MIDI note, which contains two MIDI events, note on and note off.
*
* @author Andersson, Andreen, Lanneskog, Pehrson
- * @version 1
+ * @version 2.0
*/
-public class MooNote {
+public class MooNote extends MidiEvent {
- private MidiEvent noteOnEvent, noteOffEvent;
+ private MidiEvent noteOffEvent;
private ShortMessage noteOnMsg, noteOffMsg;
- private long noteOnTime, noteOffTime;
/*
- * Creates a MooNote of the given pitch, velocity and length in the current track.
+ * Creates a MooNote from the given NoteOn event in the current track.
+ * @param noteOnEvent the NoteOn event of the note
*/
- public MooNote (int pitch, int velocity, int length) {
- noteOnMsg = new ShortMessage();
- noteOffMsg = new ShortMessage();
- noteOnMsg.setMessage(ShortMessage.NOTE_ON, pitch, velocity);
- noteOffMsg.setMessage(ShortMessage.NOTE_OFF, pitch, velocity);
-// noteOnTime = ???;
- noteOffTime = noteOnTime + length;
- noteOnEvent = new MidiEvent(noteOnMsg, noteOnTime);
- noteOffEvent = new MidiEvent(noteOffMsg, noteOffTime);
+ public MooNote (MidiEvent noteOnEvent) {
+ super(noteOnEvent.getMessage(), noteOnEvent.getTick());
+ noteOnMsg = (ShortMessage)getMessage();
+ }
+
+ /*
+ * Creates a MooNote from the given NoteOn event in the current track and creates a reference to
+ * the corresponding NoteOff event.
+ * @param noteOnEvent the NoteOn event of the note
+ * @param noteOffEvent the NoteOff event of the note
+ */
+ public MooNote (MidiEvent noteOnEvent, MidiEvent noteOffEvent) {
+ super(noteOnEvent.getMessage(), noteOnEvent.getTick());
+ noteOffEvent = new MidiEvent(noteOffEvent.getMessage(), noteOffEvent.getTick());
+ noteOnMsg = (ShortMessage)getMessage();
+ noteOffMsg = (ShortMessage)noteOffEvent.getMessage();
+ }
+
+ /*
+ * Creates a MooNote of the given pitch, velocity and duration in the current track.
+ * @param track the track to which the MooNote was added
+ * @param channel the channel of the note (1-16)
+ * @param pitch the pitch of the note (0-127)
+ * @param velocity the velocity of the note (0-127)
+ * @param timestamp the timestamp of the note in ticks (96 per beat)
+ * @param duration the duration of the note in ticks (96 per beat)
+ */
+ public MooNote (int track, int channel, int pitch, int velocity, long timestamp, int duration) {
+ super(new ShortMessage(), timestamp);
+ noteOffEvent = new MidiEvent(new ShortMessage(), timestamp + duration);
+ noteOnMsg = (ShortMessage)getMessage();
+ noteOffMsg = (ShortMessage)noteOffEvent.getMessage();
+ try {
+ noteOnMsg.setMessage(ShortMessage.NOTE_ON, channel, pitch, velocity);
+ noteOffMsg.setMessage(ShortMessage.NOTE_OFF, channel, pitch, 0);
+ } catch (InvalidMidiDataException e) {}
+ }
+
+ /*
+ * Sets the channel of the current note.
+ * @param channel the channel of the note (1-16)
+ */
+ public void setChannel(int channel) {
+ try {
+ noteOnMsg.setMessage(noteOnMsg.getCommand(), (byte)channel, noteOnMsg.getData1(), noteOnMsg.getData2());
+ noteOffMsg.setMessage(noteOffMsg.getCommand(), (byte)channel, noteOffMsg.getData1(), noteOffMsg.getData2());
+ } catch (InvalidMidiDataException e) {}
}
/*
* @param pitch the pitch of the note (0-127)
*/
public void setPitch(int pitch) {
- noteOnMsg.setMessage(ShortMessage.NOTE_ON, pitch, noteOnMsg.getData2());
- noteOffMsg.setMessage(ShortMessage.NOTE_OFF, pitch, noteOffMsg.getData2());
+ try {
+ noteOnMsg.setMessage(noteOnMsg.getCommand(), noteOnMsg.getChannel(), (byte)pitch, noteOnMsg.getData2());
+ noteOffMsg.setMessage(noteOffMsg.getCommand(), noteOffMsg.getChannel(), (byte)pitch, noteOffMsg.getData2());
+ } catch (InvalidMidiDataException e) {}
}
/*
* Sets the velocity of the current note.
- + @param vel the velocity of the note (0-127)
+ * @param vel the velocity of the note (0-127)
*/
public void setVelocity(int vel) {
- noteOnMsg.setMessage(ShortMessage.NOTE_ON, noteOnMsg.getData1(), vel);
- noteOffMsg.setMessage(ShortMessage.NOTE_OFF, noteOffMsg.getData1(), vel);
+ try {
+ noteOnMsg.setMessage(noteOnMsg.getCommand(), noteOnMsg.getChannel(), noteOnMsg.getData1(), (byte)vel);
+ noteOffMsg.setMessage(noteOffMsg.getCommand(), noteOffMsg.getChannel(), noteOffMsg.getData1(), noteOffMsg.getData2());
+ } catch (InvalidMidiDataException e) {}
}
/*
- * Sets the length of the current note (or rather moves the note off event).
- + @param n the length of the note in ticks (100 per beat)
+ * Sets the duration of the current note (or rather moves the note off event).
+ * @param n the duration of the note in ticks (96 per beat)
*/
- public void setLength(int ticks) {
-
+ public void setDuration(int ticks) {
+ if (hasNoteOffEvent()) noteOffEvent.setTick(getTick() + ticks);
}
/*
- * Returns the note on event of the current note.
- * @return the note on MidiEvent
+ * Sets the timestamp of the current note.
+ * @param tick the timestamp of the note in ticks (96 per beat)
*/
- public MidiEvent getNoteOnEvent() {
- return noteOnEvent;
+ public void setTick(long tick) {
+ if (hasNoteOffEvent()) noteOffEvent.setTick(tick + getDuration());
+ super.setTick(tick);
}
/*
- * Returns the note off event of the current note.
- * @return the note off MidiEvent
+ * Returns the channel of the current note.
+ * @return the channel of the note (1-16)
*/
- public MidiEvent getNoteOffEvent() {
- return noteOffEvent;
+ public int getChannel() {
+ return noteOnMsg.getChannel();
}
/*
* Returns the pitch of the current note.
- * @return the pitch of the note
+ * @return the pitch of the note (0-127)
*/
public int getPitch() {
return noteOnMsg.getData1();
/*
* Returns the velocity of the current note.
- * @return the velocity of the note
+ * @return the velocity of the note (0-127)
*/
public int getVelocity() {
return noteOnMsg.getData2();
}
/*
- * Returns the length of the current note.
- * @return the length of the note
+ * Returns the duration of the current note.
+ * @return the duration of the note (in ticks)
+ */
+ public int getDuration() {
+ if (!hasNoteOffEvent()) return 0;
+ return (int)(getTick() - noteOffEvent.getTick());
+ }
+
+ /*
+ * Returns whether the NoteOff event was found.
+ * @return the note off MidiEvent
*/
- public int getLength() {
-
+ public boolean hasNoteOffEvent() {
+ return noteOffEvent == null;
}
}
\ No newline at end of file
import javax.sound.midi.*;
+import javax.swing.*;
import java.io.*;
/* UPDATES
public class Moosique {
private static MooGUI gui;
- private static MooSequence seq;
+ private static Sequence seq;
private static Sequencer sequencer = null;
private static Synthesizer synthesizer = null;
- private static Receiver receiver = null;
private static MidiChannel[] channels;
- private static String file;
+ private static String filename;
private static long position;
/*
* Starts the application.
*/
public static void main (String[] args) {
- seq = new MooSequence();
- gui = new MooGUI(seq);
-
+ System.out.println("Moosique version 1.0");
// Acquires MIDI devices and connects them.
try {
sequencer = MidiSystem.getSequencer();
synthesizer.open();
sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());
} catch (MidiUnavailableException e) {
+ System.out.println("Unable to initialize MIDI devices.");
quit();
}
+ //If a filename is given as the command-line argument, attempts to load a sequence from the file.
+ try {
+ if (args.length == 1) {
+ if (!load(args[0])) seq = new Sequence(Sequence.PPQ, 96);
+ } else {
+ // Otherwise creates a new empty one.
+ seq = new Sequence(Sequence.PPQ, 96);
+ }
+ } catch (InvalidMidiDataException e) {}
+
+ // Sets up channels and GUI.
channels = synthesizer.getChannels();
+ gui = new MooGUI();
}
/*
* Returns a pointer to the current sequence.
* @return the current sequence
*/
- public static MooSequence getSequence() {
+ public static Sequence getSequence() {
return seq;
}
* Starts playback of the current sequence.
*/
public static void play() {
- sequencer.setSequence(seq.getSequence());
+ try {
+ sequencer.setSequence(seq);
+ } catch (InvalidMidiDataException e) {}
sequencer.setTickPosition(position);
sequencer.start();
}
* Loads the MooSequence in the given file.
* @param filename the filename to use
*/
- public static void load(String filename) throws IOException {
- file = filename;
- seq = new MooSequence(MidiSystem.getSequence(new File(filename)));
+ 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) {
+ JOptionPane.showMessageDialog(null, "File", "alert", JOptionPane.ERROR_MESSAGE);
+ return false;
+ }
+
+ // Sends sequence to GUI
+ gui.setSequence(seq);
+
+ // Searches the sequence for NoteOn events
+ Track[] tracks = seq.getTracks();
+ MidiEvent noteOn, noteOff = null, nextEvent;
+ MidiMessage nextMsg;
+ ShortMessage shortMsg;
+ for (int i = 0; i < tracks.length; i++) {
+ for (int j = 0; j < tracks[i].size(); j++) {
+ noteOn = tracks[i].get(j);
+ if (noteOn.getMessage() instanceof ShortMessage) {
+ if (((ShortMessage)noteOn.getMessage()).getCommand() == ShortMessage.NOTE_ON) {
+ // Finds the corresponding NoteOff event
+ for (int k = j + 1; k < tracks[i].size(); k++) {
+ nextEvent = tracks[i].get(k);
+ nextMsg = nextEvent.getMessage();
+ if (nextMsg instanceof ShortMessage) {
+ shortMsg = (ShortMessage) nextMsg;
+ if (shortMsg.getCommand() == ShortMessage.NOTE_OFF && shortMsg.getChannel() == ((ShortMessage)noteOn.getMessage()).getChannel() && shortMsg.getData1() == ((ShortMessage)noteOn.getMessage()).getData1()) {
+ noteOff = nextEvent;
+ break;
+ }
+ }
+ }
+ // Replaces the NoteOn event with a MooNote, if possible with the corresponding NoteOff event
+ tracks[i].remove(noteOn);
+ if (noteOff != null) {
+ tracks[i].add(new MooNote(noteOn, noteOff));
+ } else {
+ tracks[i].add(new MooNote(noteOn));
+ }
+ }
+ }
+ }
+ }
+ return true;
}
/*
* @param filename the filename to use
*/
public static void saveAs(String filename) throws IOException {
- MidiSystem.write(seq.getSequence(), 1, new File(filename));
+ MidiSystem.write(seq, 1, new File(filename));
}
* Saves the current sequence to the previously given filename.
*/
public static void save() throws IOException {
- saveAs(file);
+ saveAs(filename);
}
/*