jdk/src/java.desktop/share/classes/javax/sound/midi/Track.java
changeset 26037 508779ce6619
parent 26003 d630c97424bd
parent 25859 3317bb8137f4
child 40444 afabcfc2f3ef
equal deleted inserted replaced
25992:e9b05e933ddd 26037:508779ce6619
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 package javax.sound.midi;
    26 package javax.sound.midi;
    27 
    27 
    28 import java.util.Vector;
       
    29 import java.util.ArrayList;
    28 import java.util.ArrayList;
    30 import java.util.HashSet;
    29 import java.util.HashSet;
       
    30 
    31 import com.sun.media.sound.MidiUtils;
    31 import com.sun.media.sound.MidiUtils;
    32 
    32 
    33 /**
    33 /**
    34  * A MIDI track is an independent stream of MIDI events (time-stamped MIDI
    34  * A MIDI track is an independent stream of MIDI events (time-stamped MIDI data)
    35  * data) that can be stored along with other tracks in a standard MIDI file.
    35  * that can be stored along with other tracks in a standard MIDI file. The MIDI
    36  * The MIDI specification allows only 16 channels of MIDI data, but tracks
    36  * specification allows only 16 channels of MIDI data, but tracks are a way to
    37  * are a way to get around this limitation.  A MIDI file can contain any number
    37  * get around this limitation. A MIDI file can contain any number of tracks,
    38  * of tracks, each containing its own stream of up to 16 channels of MIDI data.
    38  * each containing its own stream of up to 16 channels of MIDI data.
    39  * <p>
    39  * <p>
    40  * A <code>Track</code> occupies a middle level in the hierarchy of data played
    40  * A {@code Track} occupies a middle level in the hierarchy of data played by a
    41  * by a <code>{@link Sequencer}</code>: sequencers play sequences, which contain tracks,
    41  * {@link Sequencer}: sequencers play sequences, which contain tracks, which
    42  * which contain MIDI events.  A sequencer may provide controls that mute
    42  * contain MIDI events. A sequencer may provide controls that mute or solo
    43  * or solo individual tracks.
    43  * individual tracks.
    44  * <p>
    44  * <p>
    45  * The timing information and resolution for a track is controlled by and stored
    45  * The timing information and resolution for a track is controlled by and stored
    46  * in the sequence containing the track. A given <code>Track</code>
    46  * in the sequence containing the track. A given {@code Track} is considered to
    47  * is considered to belong to the particular <code>{@link Sequence}</code> that
    47  * belong to the particular {@link Sequence} that maintains its timing. For this
    48  * maintains its timing. For this reason, a new (empty) track is created by calling the
    48  * reason, a new (empty) track is created by calling the
    49  * <code>{@link Sequence#createTrack}</code> method, rather than by directly invoking a
    49  * {@link Sequence#createTrack} method, rather than by directly invoking a
    50  * <code>Track</code> constructor.
    50  * {@code Track} constructor.
    51  * <p>
    51  * <p>
    52  * The <code>Track</code> class provides methods to edit the track by adding
    52  * The {@code Track} class provides methods to edit the track by adding or
    53  * or removing <code>MidiEvent</code> objects from it.  These operations keep
    53  * removing {@code MidiEvent} objects from it. These operations keep the event
    54  * the event list in the correct time order.  Methods are also
    54  * list in the correct time order. Methods are also included to obtain the
    55  * included to obtain the track's size, in terms of either the number of events
    55  * track's size, in terms of either the number of events it contains or its
    56  * it contains or its duration in ticks.
    56  * duration in ticks.
    57  *
    57  *
       
    58  * @author Kara Kytle
       
    59  * @author Florian Bomers
    58  * @see Sequencer#setTrackMute
    60  * @see Sequencer#setTrackMute
    59  * @see Sequencer#setTrackSolo
    61  * @see Sequencer#setTrackSolo
    60  *
       
    61  * @author Kara Kytle
       
    62  * @author Florian Bomers
       
    63  */
    62  */
    64 public class Track {
    63 public class Track {
    65 
    64 
    66     // TODO: use arrays for faster access
    65     // TODO: use arrays for faster access
    67 
    66 
    71     // use a hashset to detect duplicate events in add(MidiEvent)
    70     // use a hashset to detect duplicate events in add(MidiEvent)
    72     private HashSet<MidiEvent> set = new HashSet<>();
    71     private HashSet<MidiEvent> set = new HashSet<>();
    73 
    72 
    74     private MidiEvent eotEvent;
    73     private MidiEvent eotEvent;
    75 
    74 
    76 
    75     /**
    77     /**
    76      * Package-private constructor. Constructs a new, empty Track object, which
    78      * Package-private constructor.  Constructs a new, empty Track object,
    77      * initially contains one event, the meta-event End of Track.
    79      * which initially contains one event, the meta-event End of Track.
       
    80      */
    78      */
    81     Track() {
    79     Track() {
    82         // start with the end of track event
    80         // start with the end of track event
    83         MetaMessage eot = new ImmutableEndOfTrack();
    81         MetaMessage eot = new ImmutableEndOfTrack();
    84         eotEvent = new MidiEvent(eot, 0);
    82         eotEvent = new MidiEvent(eot, 0);
    85         eventsList.add(eotEvent);
    83         eventsList.add(eotEvent);
    86         set.add(eotEvent);
    84         set.add(eotEvent);
    87     }
    85     }
    88 
    86 
    89     /**
    87     /**
    90      * Adds a new event to the track.  However, if the event is already
    88      * Adds a new event to the track. However, if the event is already contained
    91      * contained in the track, it is not added again.  The list of events
    89      * in the track, it is not added again. The list of events is kept in time
    92      * is kept in time order, meaning that this event inserted at the
    90      * order, meaning that this event inserted at the appropriate place in the
    93      * appropriate place in the list, not necessarily at the end.
    91      * list, not necessarily at the end.
    94      *
    92      *
    95      * @param event the event to add
    93      * @param  event the event to add
    96      * @return <code>true</code> if the event did not already exist in the
    94      * @return {@code true} if the event did not already exist in the track and
    97      * track and was added, otherwise <code>false</code>
    95      *         was added, otherwise {@code false}
    98      */
    96      */
    99     public boolean add(MidiEvent event) {
    97     public boolean add(MidiEvent event) {
   100         if (event == null) {
    98         if (event == null) {
   101             return false;
    99             return false;
   102         }
   100         }
   174         }
   172         }
   175 
   173 
   176         return false;
   174         return false;
   177     }
   175     }
   178 
   176 
   179 
       
   180     /**
   177     /**
   181      * Removes the specified event from the track.
   178      * Removes the specified event from the track.
   182      * @param event the event to remove
   179      *
   183      * @return <code>true</code> if the event existed in the track and was removed,
   180      * @param  event the event to remove
   184      * otherwise <code>false</code>
   181      * @return {@code true} if the event existed in the track and was removed,
       
   182      *         otherwise {@code false}
   185      */
   183      */
   186     public boolean remove(MidiEvent event) {
   184     public boolean remove(MidiEvent event) {
   187 
   185 
   188         // this implementation allows removing the EOT event.
   186         // this implementation allows removing the EOT event.
   189         // pretty bad, but would probably be too risky to
   187         // pretty bad, but would probably be too risky to
   205             }
   203             }
   206         }
   204         }
   207         return false;
   205         return false;
   208     }
   206     }
   209 
   207 
   210 
       
   211     /**
   208     /**
   212      * Obtains the event at the specified index.
   209      * Obtains the event at the specified index.
   213      * @param index the location of the desired event in the event vector
   210      *
   214      * @throws ArrayIndexOutOfBoundsException  if the
   211      * @param  index the location of the desired event in the event vector
   215      * specified index is negative or not less than the current size of
   212      * @return the event at the specified index
   216      * this track.
   213      * @throws ArrayIndexOutOfBoundsException if the specified index is negative
       
   214      *         or not less than the current size of this track
   217      * @see #size
   215      * @see #size
   218      * @return the event at the specified index
       
   219      */
   216      */
   220     public MidiEvent get(int index) throws ArrayIndexOutOfBoundsException {
   217     public MidiEvent get(int index) throws ArrayIndexOutOfBoundsException {
   221         try {
   218         try {
   222             synchronized(eventsList) {
   219             synchronized(eventsList) {
   223                 return eventsList.get(index);
   220                 return eventsList.get(index);
   225         } catch (IndexOutOfBoundsException ioobe) {
   222         } catch (IndexOutOfBoundsException ioobe) {
   226             throw new ArrayIndexOutOfBoundsException(ioobe.getMessage());
   223             throw new ArrayIndexOutOfBoundsException(ioobe.getMessage());
   227         }
   224         }
   228     }
   225     }
   229 
   226 
   230 
       
   231     /**
   227     /**
   232      * Obtains the number of events in this track.
   228      * Obtains the number of events in this track.
       
   229      *
   233      * @return the size of the track's event vector
   230      * @return the size of the track's event vector
   234      */
   231      */
   235     public int size() {
   232     public int size() {
   236         synchronized(eventsList) {
   233         synchronized(eventsList) {
   237             return eventsList.size();
   234             return eventsList.size();
   238         }
   235         }
   239     }
   236     }
   240 
   237 
   241 
   238     /**
   242     /**
   239      * Obtains the length of the track, expressed in MIDI ticks. (The duration
   243      * Obtains the length of the track, expressed in MIDI ticks.  (The
   240      * of a tick in seconds is determined by the timing resolution of the
   244      * duration of a tick in seconds is determined by the timing resolution
   241      * {@code Sequence} containing this track, and also by the tempo of the
   245      * of the <code>Sequence</code> containing this track, and also by
   242      * music as set by the sequencer.)
   246      * the tempo of the music as set by the sequencer.)
   243      *
   247      * @return the duration, in ticks
   244      * @return the duration, in ticks
   248      * @see Sequence#Sequence(float, int)
   245      * @see Sequence#Sequence(float, int)
   249      * @see Sequencer#setTempoInBPM(float)
   246      * @see Sequencer#setTempoInBPM(float)
   250      * @see Sequencer#getTickPosition()
   247      * @see Sequencer#getTickPosition()
   251      */
   248      */
   269 
   266 
   270         public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
   267         public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
   271             throw new InvalidMidiDataException("cannot modify end of track message");
   268             throw new InvalidMidiDataException("cannot modify end of track message");
   272         }
   269         }
   273     }
   270     }
   274 
       
   275 }
   271 }