| /* Sequence.java -- A sequence of MIDI events |
| Copyright (C) 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package javax.sound.midi; |
| |
| import java.util.Iterator; |
| import java.util.Vector; |
| |
| /** |
| * Objects of this type represent sequences of MIDI messages that can be |
| * played back by a Sequencer. |
| * |
| * @author Anthony Green (green@redhat.com) |
| * @since 1.3 |
| * |
| */ |
| public class Sequence |
| { |
| /** |
| * The timing division type for this sequence (PPQ or SMPTE*) |
| */ |
| protected float divisionType; |
| |
| /** |
| * The timing resolution in ticks/beat or ticks/frame, depending on the |
| * division type. |
| */ |
| protected int resolution; |
| |
| /** |
| * The MIDI tracks used by this sequence. |
| */ |
| protected Vector tracks; |
| |
| /** |
| * Tempo-based timing. Resolution is specified in ticks per beat. |
| */ |
| public static final float PPQ = 0.0f; |
| |
| /** |
| * 24 frames/second timing. Resolution is specific in ticks per frame. |
| */ |
| public static final float SMPTE_24 = 24.0f; |
| |
| /** |
| * 25 frames/second timing. Resolution is specific in ticks per frame. |
| */ |
| public static final float SMPTE_25 = 25.0f; |
| |
| /** |
| * 30 frames/second timing. Resolution is specific in ticks per frame. |
| */ |
| public static final float SMPTE_30 = 30.0f; |
| |
| /** |
| * 29.97 frames/second timing. Resolution is specific in ticks per frame. |
| */ |
| public static final float SMPTE_30DROP = 29.97f; |
| |
| // Private helper class |
| private void init(float divisionType, int resolution, int numTracks) |
| throws InvalidMidiDataException |
| { |
| if (divisionType != PPQ |
| && divisionType != SMPTE_24 |
| && divisionType != SMPTE_25 |
| && divisionType != SMPTE_30 |
| && divisionType != SMPTE_30DROP) |
| throw new InvalidMidiDataException("Invalid division type (" |
| + divisionType + ")"); |
| |
| this.divisionType = divisionType; |
| this.resolution = resolution; |
| |
| tracks = new Vector(numTracks); |
| while (numTracks > 0) |
| tracks.set(--numTracks, new Track()); |
| } |
| |
| /** |
| * Create a MIDI sequence object with no initial tracks. |
| * |
| * @param divisionType the division type (must be one of PPQ or SMPTE_*) |
| * @param resolution the timing resolution |
| * @throws InvalidMidiDataException if the division type is invalid |
| */ |
| public Sequence(float divisionType, int resolution) |
| throws InvalidMidiDataException |
| { |
| init(divisionType, resolution, 0); |
| } |
| |
| /** |
| * Create a MIDI seqence object. |
| * |
| * @param divisionType the division type (must be one of PPQ or SMPTE_*) |
| * @param resolution the timing resolution |
| * @param numTracks the number of initial tracks |
| * @throws InvalidMidiDataException if the division type is invalid |
| */ |
| public Sequence(float divisionType, int resolution, int numTracks) |
| throws InvalidMidiDataException |
| { |
| init(divisionType, resolution, 0); |
| } |
| |
| /** |
| * The division type of this sequence. |
| * |
| * @return division type of this sequence |
| */ |
| public float getDivisionType() |
| { |
| return divisionType; |
| } |
| |
| /** |
| * The timing resolution for this sequence, relative to the division type. |
| * |
| * @return the timing resolution for this sequence |
| */ |
| public int getResolution() |
| { |
| return resolution; |
| } |
| |
| /** |
| * Create a new empty MIDI track and add it to this sequence. |
| * |
| * @return the newly create MIDI track |
| */ |
| public Track createTrack() |
| { |
| Track track = new Track(); |
| tracks.add(track); |
| return track; |
| } |
| |
| /** |
| * Remove the specified MIDI track from this sequence. |
| * |
| * @param track the track to remove |
| * @return true if track was removed and false othewise |
| */ |
| public boolean deleteTrack(Track track) |
| { |
| return tracks.remove(track); |
| } |
| |
| /** |
| * Get an array of MIDI tracks used in this sequence. |
| * |
| * @return a possibly empty array of tracks |
| */ |
| public Track[] getTracks() |
| { |
| return (Track[]) tracks.toArray(new Track[tracks.size()]); |
| } |
| |
| /** |
| * The length of this sequence in microseconds. |
| * |
| * @return the length of this sequence in microseconds |
| */ |
| public long getMicrosecondLength() |
| { |
| long tickLength = getTickLength(); |
| |
| if (divisionType == PPQ) |
| { |
| // FIXME |
| // How can this possible be computed? PPQ is pulses per quarter-note, |
| // which is dependent on the tempo of the Sequencer. |
| throw new |
| UnsupportedOperationException("Can't compute PPQ based lengths yet"); |
| } |
| else |
| { |
| // This is a fixed tick per frame computation |
| return (long) ((tickLength * 1000000) / (divisionType * resolution)); |
| } |
| } |
| |
| /** |
| * The length of this sequence in MIDI ticks. |
| * |
| * @return the length of this sequence in MIDI ticks |
| */ |
| public long getTickLength() |
| { |
| long length = 0; |
| Iterator itr = tracks.iterator(); |
| while (itr.hasNext()) |
| { |
| Track track = (Track) itr.next(); |
| long trackTicks = track.ticks(); |
| if (trackTicks > length) |
| length = trackTicks; |
| } |
| return length; |
| } |
| |
| /** |
| * Get an array of patches used in this sequence. |
| * |
| * @return an array of patches used in this sequence |
| */ |
| public Patch[] getPatchList() |
| { |
| // FIXE: not quite sure how to do this yet. |
| throw new UnsupportedOperationException("Can't get patch list yet"); |
| } |
| } |