Trackpublic class Track extends Object A MIDI track is an independent stream of MIDI events (time-stamped MIDI
data) that can be stored along with other tracks in a standard MIDI file.
The MIDI specification allows only 16 channels of MIDI data, but tracks
are a way to get around this limitation. A MIDI file can contain any number
of tracks, each containing its own stream of up to 16 channels of MIDI data.
A Track occupies a middle level in the hierarchy of data played
by a {@link Sequencer} : sequencers play sequences, which contain tracks,
which contain MIDI events. A sequencer may provide controls that mute
or solo individual tracks.
The timing information and resolution for a track is controlled by and stored
in the sequence containing the track. A given Track
is considered to belong to the particular {@link Sequence} that
maintains its timing. For this reason, a new (empty) track is created by calling the
{@link Sequence#createTrack} method, rather than by directly invoking a
Track constructor.
The Track class provides methods to edit the track by adding
or removing MidiEvent objects from it. These operations keep
the event list in the correct time order. Methods are also
included to obtain the track's size, in terms of either the number of events
it contains or its duration in ticks. |
Fields Summary |
---|
private ArrayList | eventsList | private HashSet | set | private MidiEvent | eotEvent |
Constructors Summary |
---|
Track()Package-private constructor. Constructs a new, empty Track object,
which initially contains one event, the meta-event End of Track.
// start with the end of track event
MetaMessage eot = new ImmutableEndOfTrack();
eotEvent = new MidiEvent(eot, 0);
eventsList.add(eotEvent);
set.add(eotEvent);
|
Methods Summary |
---|
public boolean | add(javax.sound.midi.MidiEvent event)Adds a new event to the track. However, if the event is already
contained in the track, it is not added again. The list of events
is kept in time order, meaning that this event inserted at the
appropriate place in the list, not necessarily at the end.
if (event == null) {
return false;
}
synchronized(eventsList) {
if (!set.contains(event)) {
int eventsCount = eventsList.size();
// get the last event
MidiEvent lastEvent = null;
if (eventsCount > 0) {
lastEvent = (MidiEvent) eventsList.get(eventsCount - 1);
}
// sanity check that we have a correct end-of-track
if (lastEvent != eotEvent) {
// if there is no eot event, add our immutable instance again
if (lastEvent != null) {
// set eotEvent's tick to the last tick of the track
eotEvent.setTick(lastEvent.getTick());
} else {
// if the events list is empty, just set the tick to 0
eotEvent.setTick(0);
}
// we needn't check for a duplicate of eotEvent in "eventsList",
// since then it would appear in the set.
eventsList.add(eotEvent);
set.add(eotEvent);
eventsCount = eventsList.size();
}
// first see if we are trying to add
// and endoftrack event.
if (MidiUtils.isMetaEndOfTrack(event.getMessage())) {
// since end of track event is useful
// for delays at the end of a track, we want to keep
// the tick value requested here if it is greater
// than the one on the eot we are maintaining.
// Otherwise, we only want a single eot event, so ignore.
if (event.getTick() > eotEvent.getTick()) {
eotEvent.setTick(event.getTick());
}
return true;
}
// prevent duplicates
set.add(event);
// insert event such that events is sorted in increasing
// tick order
int i = eventsCount;
for ( ; i > 0; i--) {
if (event.getTick() >= ((MidiEvent)eventsList.get(i-1)).getTick()) {
break;
}
}
if (i == eventsCount) {
// we're adding an event after the
// tick value of our eot, so push the eot out.
// Always add at the end for better performance:
// this saves all the checks and arraycopy when inserting
// overwrite eot with new event
eventsList.set(eventsCount - 1, event);
// set new time of eot, if necessary
if (eotEvent.getTick() < event.getTick()) {
eotEvent.setTick(event.getTick());
}
// add eot again at the end
eventsList.add(eotEvent);
} else {
eventsList.add(i, event);
}
return true;
}
}
return false;
| public javax.sound.midi.MidiEvent | get(int index)Obtains the event at the specified index.
try {
synchronized(eventsList) {
return (MidiEvent)eventsList.get(index);
}
} catch (IndexOutOfBoundsException ioobe) {
throw new ArrayIndexOutOfBoundsException(ioobe.getMessage());
}
| public boolean | remove(javax.sound.midi.MidiEvent event)Removes the specified event from the track.
// this implementation allows removing the EOT event.
// pretty bad, but would probably be too risky to
// change behavior now, in case someone does tricks like:
//
// while (track.size() > 0) track.remove(track.get(track.size() - 1));
// also, would it make sense to adjust the EOT's time
// to the last event, if the last non-EOT event is removed?
// Or: document that the ticks() length will not be reduced
// by deleting events (unless the EOT event is removed)
synchronized(eventsList) {
if (set.remove(event)) {
int i = eventsList.indexOf(event);
if (i >= 0) {
eventsList.remove(i);
return true;
}
}
}
return false;
| public int | size()Obtains the number of events in this track.
synchronized(eventsList) {
return eventsList.size();
}
| public long | ticks()Obtains the length of the track, expressed in MIDI ticks. (The
duration of a tick in seconds is determined by the timing resolution
of the Sequence containing this track, and also by
the tempo of the music as set by the sequencer.)
long ret = 0;
synchronized (eventsList) {
if (eventsList.size() > 0) {
ret = ((MidiEvent)eventsList.get(eventsList.size() - 1)).getTick();
}
}
return ret;
|
|