1 /*
   2  * Copyright (c) 1999, 2017, 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 class="striped">
  47  * <caption>MIDI File Format Properties</caption>
  48  * <thead>
  49  *   <tr>
  50  *     <th scope="col">Property key
  51  *     <th scope="col">Value type
  52  *     <th scope="col">Description
  53  * </thead>
  54  * <tbody>
  55  *   <tr>
  56  *     <th scope="row">"author"
  57  *     <td>{@link String String}
  58  *     <td>name of the author of this file
  59  *   <tr>
  60  *     <th scope="row">"title"
  61  *     <td>{@link String String}
  62  *     <td>title of this file
  63  *   <tr>
  64  *     <th scope="row">"copyright"
  65  *     <td>{@link String String}
  66  *     <td>copyright message
  67  *   <tr>
  68  *     <th scope="row">"date"
  69  *     <td>{@link java.util.Date Date}
  70  *     <td>date of the recording or release
  71  *   <tr>
  72  *     <th scope="row">"comment"
  73  *     <td>{@link String String}
  74  *     <td>an arbitrary text
  75  * </tbody>
  76  * </table>
  77  *
  78  * @author Kara Kytle
  79  * @author Florian Bomers
  80  * @see MidiSystem#getMidiFileFormat(java.io.File)
  81  * @see Sequencer#setSequence(java.io.InputStream stream)
  82  */
  83 public class MidiFileFormat {
  84 
  85     /**
  86      * Represents unknown length.
  87      *
  88      * @see #getByteLength
  89      * @see #getMicrosecondLength
  90      */
  91     public static final int UNKNOWN_LENGTH = -1;
  92 
  93     /**
  94      * The type of MIDI file.
  95      */
  96     protected int type;
  97 
  98     /**
  99      * The division type of the MIDI file.
 100      *
 101      * @see Sequence#PPQ
 102      * @see Sequence#SMPTE_24
 103      * @see Sequence#SMPTE_25
 104      * @see Sequence#SMPTE_30DROP
 105      * @see Sequence#SMPTE_30
 106      */
 107     protected float divisionType;
 108 
 109     /**
 110      * The timing resolution of the MIDI file.
 111      */
 112     protected int resolution;
 113 
 114     /**
 115      * The length of the MIDI file in bytes.
 116      */
 117     protected int byteLength;
 118 
 119     /**
 120      * The duration of the MIDI file in microseconds.
 121      */
 122     protected long microsecondLength;
 123 
 124     /**
 125      * The set of properties.
 126      */
 127     private HashMap<String, Object> properties;
 128 
 129     /**
 130      * Constructs a {@code MidiFileFormat}.
 131      *
 132      * @param  type the MIDI file type (0, 1, or 2)
 133      * @param  divisionType the timing division type (PPQ or one of the SMPTE
 134      *         types)
 135      * @param  resolution the timing resolution
 136      * @param  bytes the length of the MIDI file in bytes, or
 137      *         {@link #UNKNOWN_LENGTH} if not known
 138      * @param  microseconds the duration of the file in microseconds, or
 139      *         {@link #UNKNOWN_LENGTH} if not known
 140      * @see #UNKNOWN_LENGTH
 141      * @see Sequence#PPQ
 142      * @see Sequence#SMPTE_24
 143      * @see Sequence#SMPTE_25
 144      * @see Sequence#SMPTE_30DROP
 145      * @see Sequence#SMPTE_30
 146      */
 147     public MidiFileFormat(int type, float divisionType, int resolution, int bytes, long microseconds) {
 148 
 149         this.type = type;
 150         this.divisionType = divisionType;
 151         this.resolution = resolution;
 152         this.byteLength = bytes;
 153         this.microsecondLength = microseconds;
 154         this.properties = null;
 155     }
 156 
 157     /**
 158      * Construct a {@code MidiFileFormat} with a set of properties.
 159      *
 160      * @param  type the MIDI file type (0, 1, or 2)
 161      * @param  divisionType the timing division type (PPQ or one of the SMPTE
 162      *         types)
 163      * @param  resolution the timing resolution
 164      * @param  bytes the length of the MIDI file in bytes, or
 165      *         {@code UNKNOWN_LENGTH} if not known
 166      * @param  microseconds the duration of the file in microseconds, or
 167      *         {@code UNKNOWN_LENGTH} if not known
 168      * @param  properties a {@code Map<String,Object>} object with properties
 169      * @see #UNKNOWN_LENGTH
 170      * @see Sequence#PPQ
 171      * @see Sequence#SMPTE_24
 172      * @see Sequence#SMPTE_25
 173      * @see Sequence#SMPTE_30DROP
 174      * @see Sequence#SMPTE_30
 175      * @since 1.5
 176      */
 177     public MidiFileFormat(int type, float divisionType,
 178                           int resolution, int bytes,
 179                           long microseconds, Map<String, Object> properties) {
 180         this(type, divisionType, resolution, bytes, microseconds);
 181         this.properties = new HashMap<>(properties);
 182     }
 183 
 184     /**
 185      * Obtains the MIDI file type.
 186      *
 187      * @return the file's type (0, 1, or 2)
 188      */
 189     public int getType() {
 190         return type;
 191     }
 192 
 193     /**
 194      * Obtains the timing division type for the MIDI file.
 195      *
 196      * @return the division type (PPQ or one of the SMPTE types)
 197      * @see Sequence#Sequence(float, int)
 198      * @see Sequence#PPQ
 199      * @see Sequence#SMPTE_24
 200      * @see Sequence#SMPTE_25
 201      * @see Sequence#SMPTE_30DROP
 202      * @see Sequence#SMPTE_30
 203      * @see Sequence#getDivisionType()
 204      */
 205     public float getDivisionType() {
 206         return divisionType;
 207     }
 208 
 209     /**
 210      * Obtains the timing resolution for the MIDI file. If the division type is
 211      * PPQ, the resolution is specified in ticks per beat. For SMTPE timing, the
 212      * resolution is specified in ticks per frame.
 213      *
 214      * @return the number of ticks per beat (PPQ) or per frame (SMPTE)
 215      * @see #getDivisionType
 216      * @see Sequence#getResolution()
 217      */
 218     public int getResolution() {
 219         return resolution;
 220     }
 221 
 222     /**
 223      * Obtains the length of the MIDI file, expressed in 8-bit bytes.
 224      *
 225      * @return the number of bytes in the file, or {@code UNKNOWN_LENGTH} if not
 226      *         known
 227      * @see #UNKNOWN_LENGTH
 228      */
 229     public int getByteLength() {
 230         return byteLength;
 231     }
 232 
 233     /**
 234      * Obtains the length of the MIDI file, expressed in microseconds.
 235      *
 236      * @return the file's duration in microseconds, or {@code UNKNOWN_LENGTH} if
 237      *         not known
 238      * @see Sequence#getMicrosecondLength()
 239      * @see #getByteLength
 240      * @see #UNKNOWN_LENGTH
 241      */
 242     public long getMicrosecondLength() {
 243         return microsecondLength;
 244     }
 245 
 246     /**
 247      * Obtain an unmodifiable map of properties. The concept of properties is
 248      * further explained in the {@link MidiFileFormat class description}.
 249      *
 250      * @return a {@code Map<String,Object>} object containing all properties. If
 251      *         no properties are recognized, an empty map is returned.
 252      * @see #getProperty(String)
 253      * @since 1.5
 254      */
 255     @SuppressWarnings("unchecked") // Cast of result of clone
 256     public Map<String,Object> properties() {
 257         Map<String,Object> ret;
 258         if (properties == null) {
 259             ret = new HashMap<>(0);
 260         } else {
 261             ret = (Map<String,Object>) (properties.clone());
 262         }
 263         return Collections.unmodifiableMap(ret);
 264     }
 265 
 266     /**
 267      * Obtain the property value specified by the key. The concept of properties
 268      * is further explained in the {@link MidiFileFormat class description}.
 269      * <p>
 270      * If the specified property is not defined for a particular file format,
 271      * this method returns {@code null}.
 272      *
 273      * @param  key the key of the desired property
 274      * @return the value of the property with the specified key, or {@code null}
 275      *         if the property does not exist
 276      * @see #properties()
 277      * @since 1.5
 278      */
 279     public Object getProperty(String key) {
 280         if (properties == null) {
 281             return null;
 282         }
 283         return properties.get(key);
 284     }
 285 }