001package net.kreatious.pianoleopard.midi.event;
002
003import javax.sound.midi.ShortMessage;
004
005/**
006 * Represents a MIDI message associated with a particular channel and a
007 * timestamp in microseconds.
008 *
009 * @author Jay-R Studer
010 */
011public abstract class Event {
012    private final long time;
013    private final int channel;
014
015    /**
016     * Constructs a new {@link Event} using the specified channel.
017     *
018     * @param channel
019     *            the MIDI channel for this event between 0 and 15 inclusive.
020     * @param time
021     *            the time in microseconds when the message occurs.
022     */
023    Event(int channel, long time) {
024        if (channel < 0 || channel > 15) {
025            throw new IllegalArgumentException(channel + " is outside of the valid range [0, 15]");
026        }
027
028        this.channel = channel;
029        this.time = time;
030    }
031
032    /**
033     * Constructs a new {@link Event} using the specified {@link ShortMessage}.
034     *
035     * @param message
036     *            the message to extract associated information from
037     * @param time
038     *            the time in microseconds when the message occurs.
039     */
040    Event(ShortMessage message, long time) {
041        channel = message.getChannel();
042        this.time = time;
043    }
044
045    /**
046     * Gets the time in microseconds at which this event occurs.
047     *
048     * @return the time in microseconds when this event occurs.
049     */
050    public long getTime() {
051        return time;
052    }
053
054    /**
055     * Gets the channel on which this event occurs.
056     * <p>
057     * The channel value ranges from 0 to 15, inclusive.
058     *
059     * @return the channel on which this event occurs
060     */
061    public int getChannel() {
062        return channel;
063    }
064
065    /**
066     * Gets if this event is an off to on transition.
067     * <p>
068     * Note that an event can transition from off to on multiple times before an
069     * on to off transition occurs.
070     *
071     * @return true if this event marks the start of an interval, false
072     *         otherwise
073     */
074    public abstract boolean isOn();
075
076    /**
077     * Gets a slot that uniquely identifies which interval events belong to.
078     * <p>
079     * Equal slots are events occurring for the same channel and key.
080     *
081     * @return a uniquely identifying slot for this event
082     */
083    public abstract Slot getSlot();
084
085    /**
086     * Creates a new off event of the same type and slot with the specified
087     * timestamp.
088     *
089     * @param offTime
090     *            the off time of the created event measured in microseconds
091     * @param <T>
092     *            the type of the created event, must be the same as the
093     *            declaring class.
094     * @return a new event that is off but with the specified timestamp
095     */
096    public abstract <T extends Event> T createOff(long offTime);
097
098    @Override
099    public String toString() {
100        return "Event[" + (isOn() ? "on" : "off") + ", channel: " + channel + ", slot: " + getSlot() + ", time: "
101                + time + "]";
102    }
103}