Frames | No Frames |
1: /* Sequence.java -- A sequence of MIDI events 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.sound.midi; 40: 41: import java.util.Iterator; 42: import java.util.Vector; 43: 44: /** 45: * Objects of this type represent sequences of MIDI messages that can be 46: * played back by a Sequencer. 47: * 48: * @author Anthony Green (green@redhat.com) 49: * @since 1.3 50: * 51: */ 52: public class Sequence 53: { 54: /** 55: * The timing division type for this sequence (PPQ or SMPTE*) 56: */ 57: protected float divisionType; 58: 59: /** 60: * The timing resolution in ticks/beat or ticks/frame, depending on the 61: * division type. 62: */ 63: protected int resolution; 64: 65: /** 66: * The MIDI tracks used by this sequence. 67: */ 68: protected Vector<Track> tracks; 69: 70: /** 71: * Tempo-based timing. Resolution is specified in ticks per beat. 72: */ 73: public static final float PPQ = 0.0f; 74: 75: /** 76: * 24 frames/second timing. Resolution is specific in ticks per frame. 77: */ 78: public static final float SMPTE_24 = 24.0f; 79: 80: /** 81: * 25 frames/second timing. Resolution is specific in ticks per frame. 82: */ 83: public static final float SMPTE_25 = 25.0f; 84: 85: /** 86: * 30 frames/second timing. Resolution is specific in ticks per frame. 87: */ 88: public static final float SMPTE_30 = 30.0f; 89: 90: /** 91: * 29.97 frames/second timing. Resolution is specific in ticks per frame. 92: */ 93: public static final float SMPTE_30DROP = 29.97f; 94: 95: // Private helper class 96: private void init(float divisionType, int resolution, int numTracks) 97: throws InvalidMidiDataException 98: { 99: if (divisionType != PPQ 100: && divisionType != SMPTE_24 101: && divisionType != SMPTE_25 102: && divisionType != SMPTE_30 103: && divisionType != SMPTE_30DROP) 104: throw new InvalidMidiDataException("Invalid division type (" 105: + divisionType + ")"); 106: 107: this.divisionType = divisionType; 108: this.resolution = resolution; 109: 110: tracks = new Vector<Track>(numTracks); 111: while (numTracks > 0) 112: tracks.set(--numTracks, new Track()); 113: } 114: 115: /** 116: * Create a MIDI sequence object with no initial tracks. 117: * 118: * @param divisionType the division type (must be one of PPQ or SMPTE_*) 119: * @param resolution the timing resolution 120: * @throws InvalidMidiDataException if the division type is invalid 121: */ 122: public Sequence(float divisionType, int resolution) 123: throws InvalidMidiDataException 124: { 125: init(divisionType, resolution, 0); 126: } 127: 128: /** 129: * Create a MIDI seqence object. 130: * 131: * @param divisionType the division type (must be one of PPQ or SMPTE_*) 132: * @param resolution the timing resolution 133: * @param numTracks the number of initial tracks 134: * @throws InvalidMidiDataException if the division type is invalid 135: */ 136: public Sequence(float divisionType, int resolution, int numTracks) 137: throws InvalidMidiDataException 138: { 139: init(divisionType, resolution, 0); 140: } 141: 142: /** 143: * The division type of this sequence. 144: * 145: * @return division type of this sequence 146: */ 147: public float getDivisionType() 148: { 149: return divisionType; 150: } 151: 152: /** 153: * The timing resolution for this sequence, relative to the division type. 154: * 155: * @return the timing resolution for this sequence 156: */ 157: public int getResolution() 158: { 159: return resolution; 160: } 161: 162: /** 163: * Create a new empty MIDI track and add it to this sequence. 164: * 165: * @return the newly create MIDI track 166: */ 167: public Track createTrack() 168: { 169: Track track = new Track(); 170: tracks.add(track); 171: return track; 172: } 173: 174: /** 175: * Remove the specified MIDI track from this sequence. 176: * 177: * @param track the track to remove 178: * @return true if track was removed and false othewise 179: */ 180: public boolean deleteTrack(Track track) 181: { 182: return tracks.remove(track); 183: } 184: 185: /** 186: * Get an array of MIDI tracks used in this sequence. 187: * 188: * @return a possibly empty array of tracks 189: */ 190: public Track[] getTracks() 191: { 192: return tracks.toArray(new Track[tracks.size()]); 193: } 194: 195: /** 196: * The length of this sequence in microseconds. 197: * 198: * @return the length of this sequence in microseconds 199: */ 200: public long getMicrosecondLength() 201: { 202: long tickLength = getTickLength(); 203: 204: if (divisionType == PPQ) 205: { 206: // FIXME 207: // How can this possible be computed? PPQ is pulses per quarter-note, 208: // which is dependent on the tempo of the Sequencer. 209: throw new 210: UnsupportedOperationException("Can't compute PPQ based lengths yet"); 211: } 212: else 213: { 214: // This is a fixed tick per frame computation 215: return (long) ((tickLength * 1000000) / (divisionType * resolution)); 216: } 217: } 218: 219: /** 220: * The length of this sequence in MIDI ticks. 221: * 222: * @return the length of this sequence in MIDI ticks 223: */ 224: public long getTickLength() 225: { 226: long length = 0; 227: Iterator<Track> itr = tracks.iterator(); 228: while (itr.hasNext()) 229: { 230: Track track = itr.next(); 231: long trackTicks = track.ticks(); 232: if (trackTicks > length) 233: length = trackTicks; 234: } 235: return length; 236: } 237: 238: /** 239: * Get an array of patches used in this sequence. 240: * 241: * @return an array of patches used in this sequence 242: */ 243: public Patch[] getPatchList() 244: { 245: // FIXE: not quite sure how to do this yet. 246: throw new UnsupportedOperationException("Can't get patch list yet"); 247: } 248: }