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