Path: blob/master/src/java.desktop/share/classes/javax/sound/midi/Sequence.java
41159 views
/*1* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sound.midi;2627import java.util.Vector;2829/**30* A {@code Sequence} is a data structure containing musical information (often31* an entire song or composition) that can be played back by a {@link Sequencer}32* object. Specifically, the {@code Sequence} contains timing information and33* one or more tracks. Each {@link Track track} consists of a series of MIDI34* events (such as note-ons, note-offs, program changes, and meta-events). The35* sequence's timing information specifies the type of unit that is used to36* time-stamp the events in the sequence.37* <p>38* A {@code Sequence} can be created from a MIDI file by reading the file into39* an input stream and invoking one of the {@code getSequence} methods of40* {@link MidiSystem}. A sequence can also be built from scratch by adding new41* {@code Tracks} to an empty {@code Sequence}, and adding {@link MidiEvent}42* objects to these {@code Tracks}.43*44* @author Kara Kytle45* @see Sequencer#setSequence(java.io.InputStream stream)46* @see Sequencer#setSequence(Sequence sequence)47* @see Track#add(MidiEvent)48* @see MidiFileFormat49*/50public class Sequence {5152// Timing types5354/**55* The tempo-based timing type, for which the resolution is expressed in56* pulses (ticks) per quarter note.57*58* @see #Sequence(float, int)59*/60public static final float PPQ = 0.0f;6162/**63* The SMPTE-based timing type with 24 frames per second (resolution is64* expressed in ticks per frame).65*66* @see #Sequence(float, int)67*/68public static final float SMPTE_24 = 24.0f;6970/**71* The SMPTE-based timing type with 25 frames per second (resolution is72* expressed in ticks per frame).73*74* @see #Sequence(float, int)75*/76public static final float SMPTE_25 = 25.0f;7778/**79* The SMPTE-based timing type with 29.97 frames per second (resolution is80* expressed in ticks per frame).81*82* @see #Sequence(float, int)83*/84public static final float SMPTE_30DROP = 29.97f;8586/**87* The SMPTE-based timing type with 30 frames per second (resolution is88* expressed in ticks per frame).89*90* @see #Sequence(float, int)91*/92public static final float SMPTE_30 = 30.0f;9394// Variables9596/**97* The timing division type of the sequence.98*99* @see #PPQ100* @see #SMPTE_24101* @see #SMPTE_25102* @see #SMPTE_30DROP103* @see #SMPTE_30104* @see #getDivisionType105*/106protected float divisionType;107108/**109* The timing resolution of the sequence.110*111* @see #getResolution112*/113protected int resolution;114115/**116* The MIDI tracks in this sequence.117*118* @see #getTracks119*/120protected Vector<Track> tracks = new Vector<>();121122/**123* Constructs a new MIDI sequence with the specified timing division type124* and timing resolution. The division type must be one of the recognized125* MIDI timing types. For tempo-based timing, {@code divisionType} is PPQ126* (pulses per quarter note) and the resolution is specified in ticks per127* beat. For SMTPE timing, {@code divisionType} specifies the number of128* frames per second and the resolution is specified in ticks per frame. The129* sequence will contain no initial tracks. Tracks may be added to or130* removed from the sequence using {@link #createTrack} and131* {@link #deleteTrack}.132*133* @param divisionType the timing division type (PPQ or one of the SMPTE134* types)135* @param resolution the timing resolution136* @throws InvalidMidiDataException if {@code divisionType} is not valid137* @see #PPQ138* @see #SMPTE_24139* @see #SMPTE_25140* @see #SMPTE_30DROP141* @see #SMPTE_30142* @see #getDivisionType143* @see #getResolution144* @see #getTracks145*/146public Sequence(float divisionType, int resolution) throws InvalidMidiDataException {147148if (divisionType == PPQ)149this.divisionType = PPQ;150else if (divisionType == SMPTE_24)151this.divisionType = SMPTE_24;152else if (divisionType == SMPTE_25)153this.divisionType = SMPTE_25;154else if (divisionType == SMPTE_30DROP)155this.divisionType = SMPTE_30DROP;156else if (divisionType == SMPTE_30)157this.divisionType = SMPTE_30;158else throw new InvalidMidiDataException("Unsupported division type: " + divisionType);159160this.resolution = resolution;161}162163/**164* Constructs a new MIDI sequence with the specified timing division type,165* timing resolution, and number of tracks. The division type must be one of166* the recognized MIDI timing types. For tempo-based timing,167* {@code divisionType} is PPQ (pulses per quarter note) and the resolution168* is specified in ticks per beat. For SMTPE timing, {@code divisionType}169* specifies the number of frames per second and the resolution is specified170* in ticks per frame. The sequence will be initialized with the number of171* tracks specified by {@code numTracks}. These tracks are initially empty172* (i.e. they contain only the meta-event End of Track). The tracks may be173* retrieved for editing using the {@link #getTracks} method. Additional174* tracks may be added, or existing tracks removed, using175* {@link #createTrack} and {@link #deleteTrack}.176*177* @param divisionType the timing division type (PPQ or one of the SMPTE178* types)179* @param resolution the timing resolution180* @param numTracks the initial number of tracks in the sequence181* @throws InvalidMidiDataException if {@code divisionType} is not valid182* @see #PPQ183* @see #SMPTE_24184* @see #SMPTE_25185* @see #SMPTE_30DROP186* @see #SMPTE_30187* @see #getDivisionType188* @see #getResolution189*/190public Sequence(float divisionType, int resolution, int numTracks) throws InvalidMidiDataException {191192if (divisionType == PPQ)193this.divisionType = PPQ;194else if (divisionType == SMPTE_24)195this.divisionType = SMPTE_24;196else if (divisionType == SMPTE_25)197this.divisionType = SMPTE_25;198else if (divisionType == SMPTE_30DROP)199this.divisionType = SMPTE_30DROP;200else if (divisionType == SMPTE_30)201this.divisionType = SMPTE_30;202else throw new InvalidMidiDataException("Unsupported division type: " + divisionType);203204this.resolution = resolution;205206for (int i = 0; i < numTracks; i++) {207tracks.addElement(new Track());208}209}210211/**212* Obtains the timing division type for this sequence.213*214* @return the division type (PPQ or one of the SMPTE types)215* @see #PPQ216* @see #SMPTE_24217* @see #SMPTE_25218* @see #SMPTE_30DROP219* @see #SMPTE_30220* @see #Sequence(float, int)221* @see MidiFileFormat#getDivisionType()222*/223public float getDivisionType() {224return divisionType;225}226227/**228* Obtains the timing resolution for this sequence. If the sequence's229* division type is PPQ, the resolution is specified in ticks per beat. For230* 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 #getDivisionType234* @see #Sequence(float, int)235* @see MidiFileFormat#getResolution()236*/237public int getResolution() {238return resolution;239}240241/**242* Creates a new, initially empty track as part of this sequence. The track243* initially contains the meta-event End of Track. The newly created track244* is returned. All tracks in the sequence may be retrieved using245* {@link #getTracks}. Tracks may be removed from the sequence using246* {@link #deleteTrack}.247*248* @return the newly created track249*/250public Track createTrack() {251252Track track = new Track();253tracks.addElement(track);254255return track;256}257258/**259* Removes the specified track from the sequence.260*261* @param track the track to remove262* @return {@code true} if the track existed in the track and was removed,263* otherwise {@code false}264* @see #createTrack265* @see #getTracks266*/267public boolean deleteTrack(Track track) {268return tracks.removeElement(track);269}270271/**272* Obtains an array containing all the tracks in this sequence. If the273* sequence contains no tracks, an array of length 0 is returned.274*275* @return the array of tracks276* @see #createTrack277* @see #deleteTrack278*/279public Track[] getTracks() {280// Creation of the non-empty array will be synchronized inside toArray()281return tracks.toArray(new Track[0]);282}283284/**285* Obtains the duration of this sequence, expressed in microseconds.286*287* @return this sequence's duration in microseconds288*/289public long getMicrosecondLength() {290291return com.sun.media.sound.MidiUtils.tick2microsecond(this, getTickLength(), null);292}293294/**295* Obtains the duration of this sequence, expressed in MIDI ticks.296*297* @return this sequence's length in ticks298* @see #getMicrosecondLength299*/300public long getTickLength() {301302long length = 0;303304synchronized(tracks) {305306for(int i=0; i<tracks.size(); i++ ) {307long temp = tracks.elementAt(i).ticks();308if( temp>length ) {309length = temp;310}311}312return length;313}314}315316/**317* Obtains a list of patches referenced in this sequence. This patch list318* may be used to load the required {@link Instrument} objects into a319* {@link Synthesizer}.320*321* @return an array of {@link Patch} objects used in this sequence322* @see Synthesizer#loadInstruments(Soundbank, Patch[])323*/324public Patch[] getPatchList() {325326// $$kk: 04.09.99: need to implement!!327return new Patch[0];328}329}330331332