9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sound.midi; 27 28 import java.util.Vector; 29 import com.sun.media.sound.MidiUtils; 30 31 32 /** 33 * A <code>Sequence</code> is a data structure containing musical 34 * information (often an entire song or composition) that can be played 35 * back by a <code>{@link Sequencer}</code> object. Specifically, the 36 * <code>Sequence</code> contains timing 37 * information and one or more tracks. Each <code>{@link Track track}</code> consists of a 38 * series of MIDI events (such as note-ons, note-offs, program changes, and meta-events). 39 * The sequence's timing information specifies the type of unit that is used 40 * to time-stamp the events in the sequence. 41 * <p> 42 * A <code>Sequence</code> can be created from a MIDI file by reading the file 43 * into an input stream and invoking one of the <code>getSequence</code> methods of 44 * {@link MidiSystem}. A sequence can also be built from scratch by adding new 45 * <code>Tracks</code> to an empty <code>Sequence</code>, and adding 46 * <code>{@link MidiEvent}</code> objects to these <code>Tracks</code>. 47 * 48 * @see Sequencer#setSequence(java.io.InputStream stream) 49 * @see Sequencer#setSequence(Sequence sequence) 50 * @see Track#add(MidiEvent) 51 * @see MidiFileFormat 52 * 53 * @author Kara Kytle 54 */ 55 public class Sequence { 56 57 58 // Timing types 59 60 /** 61 * The tempo-based timing type, for which the resolution is expressed in pulses (ticks) per quarter note. 62 * @see #Sequence(float, int) 63 */ 64 public static final float PPQ = 0.0f; 65 66 /** 67 * The SMPTE-based timing type with 24 frames per second (resolution is expressed in ticks per frame). 68 * @see #Sequence(float, int) 69 */ 70 public static final float SMPTE_24 = 24.0f; 71 72 /** 73 * The SMPTE-based timing type with 25 frames per second (resolution is expressed in ticks per frame). 74 * @see #Sequence(float, int) 75 */ 76 public static final float SMPTE_25 = 25.0f; 77 78 /** 79 * The SMPTE-based timing type with 29.97 frames per second (resolution is expressed in ticks per frame). 80 * @see #Sequence(float, int) 81 */ 82 public static final float SMPTE_30DROP = 29.97f; 83 84 /** 85 * The SMPTE-based timing type with 30 frames per second (resolution is expressed in ticks per frame). 86 * @see #Sequence(float, int) 87 */ 88 public static final float SMPTE_30 = 30.0f; 89 90 91 // Variables 92 93 /** 94 * The timing division type of the sequence. 95 * @see #PPQ 96 * @see #SMPTE_24 97 * @see #SMPTE_25 98 * @see #SMPTE_30DROP 99 * @see #SMPTE_30 100 * @see #getDivisionType 101 */ 102 protected float divisionType; 103 104 /** 105 * The timing resolution of the sequence. 106 * @see #getResolution 107 */ 108 protected int resolution; 109 110 /** 111 * The MIDI tracks in this sequence. 112 * @see #getTracks 113 */ 114 protected Vector<Track> tracks = new Vector<Track>(); 115 116 117 /** 118 * Constructs a new MIDI sequence with the specified timing division 119 * type and timing resolution. The division type must be one of the 120 * recognized MIDI timing types. For tempo-based timing, 121 * <code>divisionType</code> is PPQ (pulses per quarter note) and 122 * the resolution is specified in ticks per beat. For SMTPE timing, 123 * <code>divisionType</code> specifies the number of frames per 124 * second and the resolution is specified in ticks per frame. 125 * The sequence will contain no initial tracks. Tracks may be 126 * added to or removed from the sequence using <code>{@link #createTrack}</code> 127 * and <code>{@link #deleteTrack}</code>. 128 * 129 * @param divisionType the timing division type (PPQ or one of the SMPTE types) 130 * @param resolution the timing resolution 131 * @throws InvalidMidiDataException if <code>divisionType</code> is not valid 132 * 133 * @see #PPQ 134 * @see #SMPTE_24 135 * @see #SMPTE_25 136 * @see #SMPTE_30DROP 137 * @see #SMPTE_30 138 * @see #getDivisionType 139 * @see #getResolution 140 * @see #getTracks 141 */ 142 public Sequence(float divisionType, int resolution) throws InvalidMidiDataException { 143 144 if (divisionType == PPQ) 145 this.divisionType = PPQ; 146 else if (divisionType == SMPTE_24) 147 this.divisionType = SMPTE_24; 148 else if (divisionType == SMPTE_25) 149 this.divisionType = SMPTE_25; 150 else if (divisionType == SMPTE_30DROP) 151 this.divisionType = SMPTE_30DROP; 152 else if (divisionType == SMPTE_30) 153 this.divisionType = SMPTE_30; 154 else throw new InvalidMidiDataException("Unsupported division type: " + divisionType); 155 156 this.resolution = resolution; 157 } 158 159 160 /** 161 * Constructs a new MIDI sequence with the specified timing division 162 * type, timing resolution, and number of tracks. The division type must be one of the 163 * recognized MIDI timing types. For tempo-based timing, 164 * <code>divisionType</code> is PPQ (pulses per quarter note) and 165 * the resolution is specified in ticks per beat. For SMTPE timing, 166 * <code>divisionType</code> specifies the number of frames per 167 * second and the resolution is specified in ticks per frame. 168 * The sequence will be initialized with the number of tracks specified by 169 * <code>numTracks</code>. These tracks are initially empty (i.e. 170 * they contain only the meta-event End of Track). 171 * The tracks may be retrieved for editing using the <code>{@link #getTracks}</code> 172 * method. Additional tracks may be added, or existing tracks removed, 173 * using <code>{@link #createTrack}</code> and <code>{@link #deleteTrack}</code>. 174 * 175 * @param divisionType the timing division type (PPQ or one of the SMPTE types) 176 * @param resolution the timing resolution 177 * @param numTracks the initial number of tracks in the sequence. 178 * @throws InvalidMidiDataException if <code>divisionType</code> is not valid 179 * 180 * @see #PPQ 181 * @see #SMPTE_24 182 * @see #SMPTE_25 183 * @see #SMPTE_30DROP 184 * @see #SMPTE_30 185 * @see #getDivisionType 186 * @see #getResolution 187 */ 188 public Sequence(float divisionType, int resolution, int numTracks) throws InvalidMidiDataException { 189 190 if (divisionType == PPQ) 191 this.divisionType = PPQ; 192 else if (divisionType == SMPTE_24) 193 this.divisionType = SMPTE_24; 194 else if (divisionType == SMPTE_25) 195 this.divisionType = SMPTE_25; 196 else if (divisionType == SMPTE_30DROP) 197 this.divisionType = SMPTE_30DROP; 198 else if (divisionType == SMPTE_30) 199 this.divisionType = SMPTE_30; 200 else throw new InvalidMidiDataException("Unsupported division type: " + divisionType); 201 202 this.resolution = resolution; 203 204 for (int i = 0; i < numTracks; i++) { 205 tracks.addElement(new Track()); 206 } 207 } 208 209 210 /** 211 * Obtains the timing division type for this sequence. 212 * @return the division type (PPQ or one of the SMPTE types) 213 * 214 * @see #PPQ 215 * @see #SMPTE_24 216 * @see #SMPTE_25 217 * @see #SMPTE_30DROP 218 * @see #SMPTE_30 219 * @see #Sequence(float, int) 220 * @see MidiFileFormat#getDivisionType() 221 */ 222 public float getDivisionType() { 223 return divisionType; 224 } 225 226 227 /** 228 * Obtains the timing resolution for this sequence. 229 * If the sequence's division type is PPQ, the resolution is specified in ticks per beat. 230 * For SMTPE timing, the resolution is specified in ticks per frame. 231 * 232 * @return the number of ticks per beat (PPQ) or per frame (SMPTE) 233 * @see #getDivisionType 234 * @see #Sequence(float, int) 235 * @see MidiFileFormat#getResolution() 236 */ 237 public int getResolution() { 238 return resolution; 239 } 240 241 242 /** 243 * Creates a new, initially empty track as part of this sequence. 244 * The track initially contains the meta-event End of Track. 245 * The newly created track is returned. All tracks in the sequence 246 * may be retrieved using <code>{@link #getTracks}</code>. Tracks may be 247 * removed from the sequence using <code>{@link #deleteTrack}</code>. 248 * @return the newly created track 249 */ 250 public Track createTrack() { 251 252 Track track = new Track(); 253 tracks.addElement(track); 254 255 return track; 256 } 257 258 259 /** 260 * Removes the specified track from the sequence. 261 * @param track the track to remove 262 * @return <code>true</code> if the track existed in the track and was removed, 263 * otherwise <code>false</code>. 264 * 265 * @see #createTrack 266 * @see #getTracks 267 */ 268 public boolean deleteTrack(Track track) { 269 270 synchronized(tracks) { 271 272 return tracks.removeElement(track); 273 } 274 } 275 276 277 /** 278 * Obtains an array containing all the tracks in this sequence. 279 * If the sequence contains no tracks, an array of length 0 is returned. 280 * @return the array of tracks 281 * 282 * @see #createTrack 283 * @see #deleteTrack 284 */ 285 public Track[] getTracks() { 286 287 return tracks.toArray(new Track[tracks.size()]); 288 } 289 290 291 /** 292 * Obtains the duration of this sequence, expressed in microseconds. 293 * @return this sequence's duration in microseconds. 294 */ 295 public long getMicrosecondLength() { 296 297 return com.sun.media.sound.MidiUtils.tick2microsecond(this, getTickLength(), null); 298 } 299 300 301 /** 302 * Obtains the duration of this sequence, expressed in MIDI ticks. 303 * 304 * @return this sequence's length in ticks 305 * 306 * @see #getMicrosecondLength 307 */ 308 public long getTickLength() { 309 310 long length = 0; 311 312 synchronized(tracks) { 313 314 for(int i=0; i<tracks.size(); i++ ) { 315 long temp = tracks.elementAt(i).ticks(); 316 if( temp>length ) { 317 length = temp; 318 } 319 } 320 return length; 321 } 322 } 323 324 325 /** 326 * Obtains a list of patches referenced in this sequence. 327 * This patch list may be used to load the required 328 * <code>{@link Instrument}</code> objects 329 * into a <code>{@link Synthesizer}</code>. 330 * 331 * @return an array of <code>{@link Patch}</code> objects used in this sequence 332 * 333 * @see Synthesizer#loadInstruments(Soundbank, Patch[]) 334 */ 335 public Patch[] getPatchList() { 336 337 // $$kk: 04.09.99: need to implement!! 338 return new Patch[0]; 339 } 340 } | 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sound.midi; 27 28 import java.util.Vector; 29 30 /** 31 * A {@code Sequence} is a data structure containing musical information (often 32 * an entire song or composition) that can be played back by a {@link Sequencer} 33 * object. Specifically, the {@code Sequence} contains timing information and 34 * one or more tracks. Each {@link Track track} consists of a series of MIDI 35 * events (such as note-ons, note-offs, program changes, and meta-events). The 36 * sequence's timing information specifies the type of unit that is used to 37 * time-stamp the events in the sequence. 38 * <p> 39 * A {@code Sequence} can be created from a MIDI file by reading the file into 40 * an input stream and invoking one of the {@code getSequence} methods of 41 * {@link MidiSystem}. A sequence can also be built from scratch by adding new 42 * {@code Tracks} to an empty {@code Sequence}, and adding {@link MidiEvent} 43 * objects to these {@code Tracks}. 44 * 45 * @author Kara Kytle 46 * @see Sequencer#setSequence(java.io.InputStream stream) 47 * @see Sequencer#setSequence(Sequence sequence) 48 * @see Track#add(MidiEvent) 49 * @see MidiFileFormat 50 */ 51 public class Sequence { 52 53 // Timing types 54 55 /** 56 * The tempo-based timing type, for which the resolution is expressed in 57 * pulses (ticks) per quarter note. 58 * 59 * @see #Sequence(float, int) 60 */ 61 public static final float PPQ = 0.0f; 62 63 /** 64 * The SMPTE-based timing type with 24 frames per second (resolution is 65 * expressed in ticks per frame). 66 * 67 * @see #Sequence(float, int) 68 */ 69 public static final float SMPTE_24 = 24.0f; 70 71 /** 72 * The SMPTE-based timing type with 25 frames per second (resolution is 73 * expressed in ticks per frame). 74 * 75 * @see #Sequence(float, int) 76 */ 77 public static final float SMPTE_25 = 25.0f; 78 79 /** 80 * The SMPTE-based timing type with 29.97 frames per second (resolution is 81 * expressed in ticks per frame). 82 * 83 * @see #Sequence(float, int) 84 */ 85 public static final float SMPTE_30DROP = 29.97f; 86 87 /** 88 * The SMPTE-based timing type with 30 frames per second (resolution is 89 * expressed in ticks per frame). 90 * 91 * @see #Sequence(float, int) 92 */ 93 public static final float SMPTE_30 = 30.0f; 94 95 // Variables 96 97 /** 98 * The timing division type of the sequence. 99 * 100 * @see #PPQ 101 * @see #SMPTE_24 102 * @see #SMPTE_25 103 * @see #SMPTE_30DROP 104 * @see #SMPTE_30 105 * @see #getDivisionType 106 */ 107 protected float divisionType; 108 109 /** 110 * The timing resolution of the sequence. 111 * 112 * @see #getResolution 113 */ 114 protected int resolution; 115 116 /** 117 * The MIDI tracks in this sequence. 118 * 119 * @see #getTracks 120 */ 121 protected Vector<Track> tracks = new Vector<Track>(); 122 123 /** 124 * Constructs a new MIDI sequence with the specified timing division type 125 * and timing resolution. The division type must be one of the recognized 126 * MIDI timing types. For tempo-based timing, {@code divisionType} is PPQ 127 * (pulses per quarter note) and the resolution is specified in ticks per 128 * beat. For SMTPE timing, {@code divisionType} specifies the number of 129 * frames per second and the resolution is specified in ticks per frame. The 130 * sequence will contain no initial tracks. Tracks may be added to or 131 * removed from the sequence using {@link #createTrack} and 132 * {@link #deleteTrack}. 133 * 134 * @param divisionType the timing division type (PPQ or one of the SMPTE 135 * types) 136 * @param resolution the timing resolution 137 * @throws InvalidMidiDataException if {@code divisionType} is not valid 138 * @see #PPQ 139 * @see #SMPTE_24 140 * @see #SMPTE_25 141 * @see #SMPTE_30DROP 142 * @see #SMPTE_30 143 * @see #getDivisionType 144 * @see #getResolution 145 * @see #getTracks 146 */ 147 public Sequence(float divisionType, int resolution) throws InvalidMidiDataException { 148 149 if (divisionType == PPQ) 150 this.divisionType = PPQ; 151 else if (divisionType == SMPTE_24) 152 this.divisionType = SMPTE_24; 153 else if (divisionType == SMPTE_25) 154 this.divisionType = SMPTE_25; 155 else if (divisionType == SMPTE_30DROP) 156 this.divisionType = SMPTE_30DROP; 157 else if (divisionType == SMPTE_30) 158 this.divisionType = SMPTE_30; 159 else throw new InvalidMidiDataException("Unsupported division type: " + divisionType); 160 161 this.resolution = resolution; 162 } 163 164 /** 165 * Constructs a new MIDI sequence with the specified timing division type, 166 * timing resolution, and number of tracks. The division type must be one of 167 * the recognized MIDI timing types. For tempo-based timing, 168 * {@code divisionType} is PPQ (pulses per quarter note) and the resolution 169 * is specified in ticks per beat. For SMTPE timing, {@code divisionType} 170 * specifies the number of frames per second and the resolution is specified 171 * in ticks per frame. The sequence will be initialized with the number of 172 * tracks specified by {@code numTracks}. These tracks are initially empty 173 * (i.e. they contain only the meta-event End of Track). The tracks may be 174 * retrieved for editing using the {@link #getTracks} method. Additional 175 * tracks may be added, or existing tracks removed, using 176 * {@link #createTrack} and {@link #deleteTrack}. 177 * 178 * @param divisionType the timing division type (PPQ or one of the SMPTE 179 * types) 180 * @param resolution the timing resolution 181 * @param numTracks the initial number of tracks in the sequence 182 * @throws InvalidMidiDataException if {@code divisionType} is not valid 183 * @see #PPQ 184 * @see #SMPTE_24 185 * @see #SMPTE_25 186 * @see #SMPTE_30DROP 187 * @see #SMPTE_30 188 * @see #getDivisionType 189 * @see #getResolution 190 */ 191 public Sequence(float divisionType, int resolution, int numTracks) throws InvalidMidiDataException { 192 193 if (divisionType == PPQ) 194 this.divisionType = PPQ; 195 else if (divisionType == SMPTE_24) 196 this.divisionType = SMPTE_24; 197 else if (divisionType == SMPTE_25) 198 this.divisionType = SMPTE_25; 199 else if (divisionType == SMPTE_30DROP) 200 this.divisionType = SMPTE_30DROP; 201 else if (divisionType == SMPTE_30) 202 this.divisionType = SMPTE_30; 203 else throw new InvalidMidiDataException("Unsupported division type: " + divisionType); 204 205 this.resolution = resolution; 206 207 for (int i = 0; i < numTracks; i++) { 208 tracks.addElement(new Track()); 209 } 210 } 211 212 /** 213 * Obtains the timing division type for this sequence. 214 * 215 * @return the division type (PPQ or one of the SMPTE types) 216 * @see #PPQ 217 * @see #SMPTE_24 218 * @see #SMPTE_25 219 * @see #SMPTE_30DROP 220 * @see #SMPTE_30 221 * @see #Sequence(float, int) 222 * @see MidiFileFormat#getDivisionType() 223 */ 224 public float getDivisionType() { 225 return divisionType; 226 } 227 228 /** 229 * Obtains the timing resolution for this sequence. If the sequence's 230 * division type is PPQ, the resolution is specified in ticks per beat. For 231 * SMTPE timing, the resolution is specified in ticks per frame. 232 * 233 * @return the number of ticks per beat (PPQ) or per frame (SMPTE) 234 * @see #getDivisionType 235 * @see #Sequence(float, int) 236 * @see MidiFileFormat#getResolution() 237 */ 238 public int getResolution() { 239 return resolution; 240 } 241 242 /** 243 * Creates a new, initially empty track as part of this sequence. The track 244 * initially contains the meta-event End of Track. The newly created track 245 * is returned. All tracks in the sequence may be retrieved using 246 * {@link #getTracks}. Tracks may be removed from the sequence using 247 * {@link #deleteTrack}. 248 * 249 * @return the newly created track 250 */ 251 public Track createTrack() { 252 253 Track track = new Track(); 254 tracks.addElement(track); 255 256 return track; 257 } 258 259 /** 260 * Removes the specified track from the sequence. 261 * 262 * @param track the track to remove 263 * @return {@code true} if the track existed in the track and was removed, 264 * otherwise {@code false} 265 * @see #createTrack 266 * @see #getTracks 267 */ 268 public boolean deleteTrack(Track track) { 269 270 synchronized(tracks) { 271 272 return tracks.removeElement(track); 273 } 274 } 275 276 /** 277 * Obtains an array containing all the tracks in this sequence. If the 278 * sequence contains no tracks, an array of length 0 is returned. 279 * 280 * @return the array of tracks 281 * @see #createTrack 282 * @see #deleteTrack 283 */ 284 public Track[] getTracks() { 285 286 return tracks.toArray(new Track[tracks.size()]); 287 } 288 289 /** 290 * Obtains the duration of this sequence, expressed in microseconds. 291 * 292 * @return this sequence's duration in microseconds 293 */ 294 public long getMicrosecondLength() { 295 296 return com.sun.media.sound.MidiUtils.tick2microsecond(this, getTickLength(), null); 297 } 298 299 /** 300 * Obtains the duration of this sequence, expressed in MIDI ticks. 301 * 302 * @return this sequence's length in ticks 303 * @see #getMicrosecondLength 304 */ 305 public long getTickLength() { 306 307 long length = 0; 308 309 synchronized(tracks) { 310 311 for(int i=0; i<tracks.size(); i++ ) { 312 long temp = tracks.elementAt(i).ticks(); 313 if( temp>length ) { 314 length = temp; 315 } 316 } 317 return length; 318 } 319 } 320 321 /** 322 * Obtains a list of patches referenced in this sequence. This patch list 323 * may be used to load the required {@link Instrument} objects into a 324 * {@link Synthesizer}. 325 * 326 * @return an array of {@link Patch} objects used in this sequence 327 * @see Synthesizer#loadInstruments(Soundbank, Patch[]) 328 */ 329 public Patch[] getPatchList() { 330 331 // $$kk: 04.09.99: need to implement!! 332 return new Patch[0]; 333 } 334 } |