1 /*
   2  * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   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.Collections;
  29 import java.util.HashMap;
  30 import java.util.Map;
  31 
  32 /**
  33  * A {@code MidiFileFormat} object encapsulates a MIDI file's type, as well as
  34  * its length and timing information.
  35  * <p>
  36  * A {@code MidiFileFormat} object can include a set of properties. A property
  37  * is a pair of key and value: the key is of type {@code String}, the associated
  38  * property value is an arbitrary object. Properties specify additional
  39  * informational meta data (like a author, or copyright). Properties are
  40  * optional information, and file reader and file writer implementations are not
  41  * required to provide or recognize properties.
  42  * <p>
  43  * The following table lists some common properties that should be used in
  44  * implementations:
  45  *
  46  * <table border=1>
  47     <caption>MIDI File Format Properties</caption>
  48  *  <tr>
  49  *   <th>Property key</th>
  50  *   <th>Value type</th>
  51  *   <th>Description</th>
  52  *  </tr>
  53  *  <tr>
  54  *   <td>&quot;author&quot;</td>
  55  *   <td>{@link java.lang.String String}</td>
  56  *   <td>name of the author of this file</td>
  57  *  </tr>
  58  *  <tr>
  59  *   <td>&quot;title&quot;</td>
  60  *   <td>{@link java.lang.String String}</td>
  61  *   <td>title of this file</td>
  62  *  </tr>
  63  *  <tr>
  64  *   <td>&quot;copyright&quot;</td>
  65  *   <td>{@link java.lang.String String}</td>
  66  *   <td>copyright message</td>
  67  *  </tr>
  68  *  <tr>
  69  *   <td>&quot;date&quot;</td>
  70  *   <td>{@link java.util.Date Date}</td>
  71  *   <td>date of the recording or release</td>
  72  *  </tr>
  73  *  <tr>
  74  *   <td>&quot;comment&quot;</td>
  75  *   <td>{@link java.lang.String String}</td>
  76  *   <td>an arbitrary text</td>
  77  *  </tr>
  78  * </table>
  79  *
  80  * @author Kara Kytle
  81  * @author Florian Bomers
  82  * @see MidiSystem#getMidiFileFormat(java.io.File)
  83  * @see Sequencer#setSequence(java.io.InputStream stream)
  84  */
  85 public class MidiFileFormat {
  86 
  87     /**
  88      * Represents unknown length.
  89      *
  90      * @see #getByteLength
  91      * @see #getMicrosecondLength
  92      */
  93     public static final int UNKNOWN_LENGTH = -1;
  94 
  95     /**
  96      * The type of MIDI file.
  97      */
  98     protected int type;
  99 
 100     /**
 101      * The division type of the MIDI file.
 102      *
 103      * @see Sequence#PPQ
 104      * @see Sequence#SMPTE_24
 105      * @see Sequence#SMPTE_25
 106      * @see Sequence#SMPTE_30DROP
 107      * @see Sequence#SMPTE_30
 108      */
 109     protected float divisionType;
 110 
 111     /**
 112      * The timing resolution of the MIDI file.
 113      */
 114     protected int resolution;
 115 
 116     /**
 117      * The length of the MIDI file in bytes.
 118      */
 119     protected int byteLength;
 120 
 121     /**
 122      * The duration of the MIDI file in microseconds.
 123      */
 124     protected long microsecondLength;
 125 
 126     /**
 127      * The set of properties.
 128      */
 129     private HashMap<String, Object> properties;
 130 
 131     /**
 132      * Constructs a {@code MidiFileFormat}.
 133      *
 134      * @param  type the MIDI file type (0, 1, or 2)
 135      * @param  divisionType the timing division type (PPQ or one of the SMPTE
 136      *         types)
 137      * @param  resolution the timing resolution
 138      * @param  bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if
 139      *         not known
 140      * @param  microseconds the duration of the file in microseconds, or
 141      *         UNKNOWN_LENGTH if not known
 142      * @see #UNKNOWN_LENGTH
 143      * @see Sequence#PPQ
 144      * @see Sequence#SMPTE_24
 145      * @see Sequence#SMPTE_25
 146      * @see Sequence#SMPTE_30DROP
 147      * @see Sequence#SMPTE_30
 148      */
 149     public MidiFileFormat(int type, float divisionType, int resolution, int bytes, long microseconds) {
 150 
 151         this.type = type;
 152         this.divisionType = divisionType;
 153         this.resolution = resolution;
 154         this.byteLength = bytes;
 155         this.microsecondLength = microseconds;
 156         this.properties = null;
 157     }
 158 
 159     /**
 160      * Construct a {@code MidiFileFormat} with a set of properties.
 161      *
 162      * @param  type the MIDI file type (0, 1, or 2)
 163      * @param  divisionType the timing division type (PPQ or one of the SMPTE
 164      *         types)
 165      * @param  resolution the timing resolution
 166      * @param  bytes the length of the MIDI file in bytes, or UNKNOWN_LENGTH if
 167      *         not known
 168      * @param  microseconds the duration of the file in microseconds, or
 169      *         UNKNOWN_LENGTH if not known
 170      * @param  properties a {@code Map<String,Object>} object with properties
 171      * @see #UNKNOWN_LENGTH
 172      * @see Sequence#PPQ
 173      * @see Sequence#SMPTE_24
 174      * @see Sequence#SMPTE_25
 175      * @see Sequence#SMPTE_30DROP
 176      * @see Sequence#SMPTE_30
 177      * @since 1.5
 178      */
 179     public MidiFileFormat(int type, float divisionType,
 180                           int resolution, int bytes,
 181                           long microseconds, Map<String, Object> properties) {
 182         this(type, divisionType, resolution, bytes, microseconds);
 183         this.properties = new HashMap<>(properties);
 184     }
 185 
 186     /**
 187      * Obtains the MIDI file type.
 188      *
 189      * @return the file's type (0, 1, or 2)
 190      */
 191     public int getType() {
 192         return type;
 193     }
 194 
 195     /**
 196      * Obtains the timing division type for the MIDI file.
 197      *
 198      * @return the division type (PPQ or one of the SMPTE types)
 199      * @see Sequence#Sequence(float, int)
 200      * @see Sequence#PPQ
 201      * @see Sequence#SMPTE_24
 202      * @see Sequence#SMPTE_25
 203      * @see Sequence#SMPTE_30DROP
 204      * @see Sequence#SMPTE_30
 205      * @see Sequence#getDivisionType()
 206      */
 207     public float getDivisionType() {
 208         return divisionType;
 209     }
 210 
 211     /**
 212      * Obtains the timing resolution for the MIDI file. If the division type is
 213      * PPQ, the resolution is specified in ticks per beat. For SMTPE timing, the
 214      * resolution is specified in ticks per frame.
 215      *
 216      * @return the number of ticks per beat (PPQ) or per frame (SMPTE)
 217      * @see #getDivisionType
 218      * @see Sequence#getResolution()
 219      */
 220     public int getResolution() {
 221         return resolution;
 222     }
 223 
 224     /**
 225      * Obtains the length of the MIDI file, expressed in 8-bit bytes.
 226      *
 227      * @return the number of bytes in the file, or UNKNOWN_LENGTH if not known
 228      * @see #UNKNOWN_LENGTH
 229      */
 230     public int getByteLength() {
 231         return byteLength;
 232     }
 233 
 234     /**
 235      * Obtains the length of the MIDI file, expressed in microseconds.
 236      *
 237      * @return the file's duration in microseconds, or UNKNOWN_LENGTH if not
 238      *         known
 239      * @see Sequence#getMicrosecondLength()
 240      * @see #getByteLength
 241      * @see #UNKNOWN_LENGTH
 242      */
 243     public long getMicrosecondLength() {
 244         return microsecondLength;
 245     }
 246 
 247     /**
 248      * Obtain an unmodifiable map of properties. The concept of properties is
 249      * further explained in the {@link MidiFileFormat class description}.
 250      *
 251      * @return a {@code Map<String,Object>} object containing all properties. If
 252      *         no properties are recognized, an empty map is returned.
 253      * @see #getProperty(String)
 254      * @since 1.5
 255      */
 256     @SuppressWarnings("unchecked") // Cast of result of clone
 257     public Map<String,Object> properties() {
 258         Map<String,Object> ret;
 259         if (properties == null) {
 260             ret = new HashMap<>(0);
 261         } else {
 262             ret = (Map<String,Object>) (properties.clone());
 263         }
 264         return Collections.unmodifiableMap(ret);
 265     }
 266 
 267     /**
 268      * Obtain the property value specified by the key. The concept of properties
 269      * is further explained in the {@link MidiFileFormat class description}.
 270      * <p>
 271      * If the specified property is not defined for a particular file format,
 272      * this method returns {@code null}.
 273      *
 274      * @param  key the key of the desired property
 275      * @return the value of the property with the specified key, or {@code null}
 276      *         if the property does not exist
 277      * @see #properties()
 278      * @since 1.5
 279      */
 280     public Object getProperty(String key) {
 281         if (properties == null) {
 282             return null;
 283         }
 284         return properties.get(key);
 285     }
 286 }