From: Einar Pehrson Date: Sun, 27 Apr 2003 01:12:07 +0000 (+0000) Subject: Implemented most of MooNote and Moosique X-Git-Url: https://ruin.nu/git/?p=moosique.git;a=commitdiff_plain;h=dc7477835f6d61c4235b7fbe36f97fec553e2f81 Implemented most of MooNote and Moosique Added one method to MooGUI --- diff --git a/MooGUI.java b/MooGUI.java index dcb52da..0095f42 100644 --- a/MooGUI.java +++ b/MooGUI.java @@ -1,3 +1,4 @@ +import javax.sound.midi.*; import javax.swing.*; /* @@ -9,17 +10,20 @@ import javax.swing.*; public class MooGUI { + Sequence seq; + /* * Creates the GUI. */ public MooGUI () { } - + /* - * + * Changes the sequence of the GUI. + * @param sequence the MIDI sequence to visualize */ - public void () { - + public void setSequence(Sequence sequence) { + seq = sequence; } } diff --git a/MooNote.java b/MooNote.java index d57772b..12e1238 100644 --- a/MooNote.java +++ b/MooNote.java @@ -4,27 +4,65 @@ import javax.sound.midi.*; * 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) {} } /* @@ -32,46 +70,51 @@ public class MooNote { * @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(); @@ -79,17 +122,26 @@ public class MooNote { /* * 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 diff --git a/Moosique.java b/Moosique.java index 4cf8965..792a7f2 100644 --- a/Moosique.java +++ b/Moosique.java @@ -1,4 +1,5 @@ import javax.sound.midi.*; +import javax.swing.*; import java.io.*; /* UPDATES @@ -23,23 +24,20 @@ import java.io.*; 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(); @@ -48,17 +46,30 @@ public class Moosique { 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; } @@ -66,7 +77,9 @@ public class Moosique { * 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(); } @@ -129,9 +142,55 @@ public class Moosique { * 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; } /* @@ -139,7 +198,7 @@ public class Moosique { * @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)); } @@ -147,7 +206,7 @@ public class Moosique { * Saves the current sequence to the previously given filename. */ public static void save() throws IOException { - saveAs(file); + saveAs(filename); } /*