1 import javax.sound.midi.*;
4 * Functional representation of a MIDI note, which adds functionality to the existent MidiEvent class.
5 * Also provides a reference to the corresponding NoteOff event.
7 * @author Einar Pehrson
10 public class MooNote extends MidiEvent {
12 protected MidiEvent noteOffEvent;
13 protected ShortMessage noteOnMsg, noteOffMsg;
16 * Creates a MooNote from the given NoteOn event in the current track.
17 * @param noteOnEvent the NoteOn event of the note
19 public MooNote (MidiEvent noteOnEvent) {
20 super(noteOnEvent.getMessage(), noteOnEvent.getTick());
21 noteOnMsg = (ShortMessage)getMessage();
25 * Creates a MooNote from the given NoteOn event in the current track and creates a reference to
26 * the corresponding NoteOff event.
27 * @param noteOnEvent the NoteOn event of the note
28 * @param noteOffEvent the NoteOff event of the note
30 public MooNote (MidiEvent noteOnEvent, MidiEvent noteOffEvent) {
31 super(noteOnEvent.getMessage(), noteOnEvent.getTick());
32 this.noteOffEvent = noteOffEvent;
33 noteOnMsg = (ShortMessage)getMessage();
34 noteOffMsg = (ShortMessage)noteOffEvent.getMessage();
38 * Creates a MooNote of the given pitch, velocity and duration in the current track.
39 * @param channel the channel of the note (1-16)
40 * @param pitch the pitch of the note (0-127)
41 * @param velocity the velocity of the note (0-127)
42 * @param timestamp the timestamp of the note in ticks (96 per beat)
43 * @param duration the duration of the note in ticks (96 per beat)
45 public MooNote (int channel, int pitch, int velocity, long timestamp, int duration) {
46 super(new ShortMessage(), timestamp);
47 noteOffEvent = new MidiEvent(new ShortMessage(), timestamp + duration);
48 noteOnMsg = (ShortMessage)getMessage();
49 noteOffMsg = (ShortMessage)noteOffEvent.getMessage();
51 noteOnMsg.setMessage(ShortMessage.NOTE_ON, channel, pitch, velocity);
52 noteOffMsg.setMessage(ShortMessage.NOTE_OFF, channel, pitch, 0);
53 } catch (InvalidMidiDataException e) {System.out.println("Invalid data!");}
57 * Sets the channel of the current note.
58 * @param channel the channel of the note (1-16)
60 public void setChannel(int channel) {
62 noteOnMsg.setMessage(noteOnMsg.getCommand(), (byte)channel, noteOnMsg.getData1(), noteOnMsg.getData2());
63 if(hasNoteOffEvent()) noteOffMsg.setMessage(noteOffMsg.getCommand(), (byte)channel, noteOffMsg.getData1(), noteOffMsg.getData2());
64 } catch (InvalidMidiDataException e) {}
68 * Sets the pitch of the current note.
69 * @param pitch the pitch of the note (0-127)
71 public void setPitch(int pitch) {
73 noteOnMsg.setMessage(noteOnMsg.getCommand(), noteOnMsg.getChannel(), (byte)pitch, noteOnMsg.getData2());
74 if(hasNoteOffEvent()) noteOffMsg.setMessage(noteOffMsg.getCommand(), noteOffMsg.getChannel(), (byte)pitch, noteOffMsg.getData2());
75 } catch (InvalidMidiDataException e) {}
79 * Transposes the current note the given number of halftones.
80 * @param halftones the number of halftones to transpose - positive for up, negative for down
82 public void transpose(int halftones) {
83 setPitch(getPitch() + halftones);
87 * Sets the velocity of the current note.
88 * @param vel the velocity of the note (0-127)
90 public void setVelocity(int vel) {
92 noteOnMsg.setMessage(noteOnMsg.getCommand(), noteOnMsg.getChannel(), noteOnMsg.getData1(), (byte)vel);
93 if(hasNoteOffEvent()) noteOffMsg.setMessage(noteOffMsg.getCommand(), noteOffMsg.getChannel(), noteOffMsg.getData1(), noteOffMsg.getData2());
94 } catch (InvalidMidiDataException e) {}
98 * Sets the duration of the current note (or rather moves the note off event).
99 * @param n the duration of the note in ticks (96 per beat)
101 public void setDuration(int ticks) {
102 if (hasNoteOffEvent()) noteOffEvent.setTick(getTick() + ticks);
106 * Sets the timestamp of the current note.
107 * @param tick the timestamp of the note in ticks (96 per beat)
109 public void setTick(long tick) {
110 if (hasNoteOffEvent()) noteOffEvent.setTick(tick + getDuration());
115 * Returns the channel of the current note.
116 * @return the channel of the note (1-16)
118 public int getChannel() {
119 return noteOnMsg.getChannel();
123 * Returns the pitch of the current note.
124 * @return the pitch of the note (0-127)
126 public int getPitch() {
127 return noteOnMsg.getData1();
131 * Returns the velocity of the current note.
132 * @return the velocity of the note (0-127)
134 public int getVelocity() {
135 return noteOnMsg.getData2();
139 * Returns the duration of the current note.
140 * @return the duration of the note (in ticks)
142 public int getDuration() {
143 if (!hasNoteOffEvent()) return 0;
144 return (int)(noteOffEvent.getTick() - getTick());
148 * Returns whether the NoteOff event was found.
149 * @return the note off MidiEvent
151 public boolean hasNoteOffEvent() {
152 return noteOffEvent != null;
156 * Adds this note (both noteOn and noteOffEvents) to a track.
157 * @param track the track it'll be added to.
159 public void addTo(Track track){
161 if (hasNoteOffEvent()) track.add(noteOffEvent);
165 * Removes this note (both noteOn and noteOffEvents) from a track.
166 * @param track the track it'll be removed from.
168 public void removeFrom(Track track){
170 if (hasNoteOffEvent()) track.remove(noteOffEvent);