001    /* An audio format
002       Copyright (C) 2005 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.sound.sampled;
040    
041    import java.util.Collections;
042    import java.util.HashMap;
043    import java.util.Map;
044    
045    /**
046     * This class describes an audio format, including its encoding,
047     * the number of channels, its frame rate, etc.
048     * @since 1.3
049     */
050    public class AudioFormat
051    {
052      /**
053       * This describes a given audio format encoding.
054       * @since 1.3
055       */
056      public static class Encoding
057      {
058        /** The ALAW encoding.  */
059        public static final Encoding ALAW = new Encoding("alaw");
060    
061        /** The signed PCM encoding.  */
062        public static final Encoding PCM_SIGNED = new Encoding("pcm_signed");
063    
064        /** The unsigned PCM encoding.  */
065        public static final Encoding PCM_UNSIGNED = new Encoding("pcm_unsigned");
066    
067        /** The ULAW encoding.  */
068        public static final Encoding ULAW = new Encoding("ulaw");
069    
070        private String name;
071    
072        /**
073         * Create a new encoding descriptor, given its name.
074         * @param name the name
075         */
076        public Encoding(String name)
077        {
078          this.name = name;
079        }
080    
081        public final boolean equals(Object o)
082        {
083          return super.equals(o);
084        }
085    
086        public final int hashCode()
087        {
088          return super.hashCode();
089        }
090    
091        /**
092         * Return the name of this encoding.
093         */
094        public final String toString()
095        {
096          return name;
097        }
098      }
099    
100      /**
101       * True if the audio data is stored big-endian.
102       */
103      protected boolean bigEndian;
104    
105      /**
106       * The number of channels of data in this format.
107       */
108      protected int channels;
109    
110      /**
111       * The encoding of this format.
112       */
113      protected Encoding encoding;
114    
115      /**
116       * The frame rate of this format.  This is the number of frames
117       * per second.
118       */
119      protected float frameRate;
120    
121      /**
122       * The number of bytes per frame in this format.
123       */
124      protected int frameSize;
125    
126      /**
127       * The number of samples per second.
128       */
129      protected float sampleRate;
130    
131      /**
132       * The number of bits in each sample.
133       */
134      protected int sampleSizeInBits;
135    
136      private Map<String, Object> properties;
137    
138      /**
139       * Create a new audio format, given various attributes of it.
140       * The properties map for this format will be empty.
141       * 
142       * @param encoding the encoding for this format
143       * @param sampleRate the sample rate
144       * @param sampleSizeInBits the sample size, in bits
145       * @param channels the number of channels
146       * @param frameSize the frame size, in bytes
147       * @param frameRate the frame rate, in frames per second
148       * @param bigEndian true if the data is stored big-endian
149       */
150      public AudioFormat(Encoding encoding, float sampleRate, int sampleSizeInBits,
151                         int channels, int frameSize, float frameRate,
152                         boolean bigEndian)
153      {
154        this.encoding = encoding;
155        this.sampleRate = sampleRate;
156        this.sampleSizeInBits = sampleSizeInBits;
157        this.channels = channels;
158        this.frameSize = frameSize;
159        this.frameRate = frameRate;
160        this.bigEndian = bigEndian;
161        this.properties = Collections.<String, Object> emptyMap();
162      }
163    
164      /**
165       * Create a new audio format, given various attributes of it.
166       * The properties map is copied by this constructor, so changes
167       * to the argument Map will not affect the new object.
168       *
169       * @param encoding the encoding for this format
170       * @param sampleRate the sample rate
171       * @param sampleSizeInBits the sample size, in bits
172       * @param channels the number of channels
173       * @param frameSize the frame size, in bytes
174       * @param frameRate the frame rate, in frames per second
175       * @param bigEndian true if the data is stored big-endian
176       * @param properties a map describing properties of this format
177       */
178      public AudioFormat(Encoding encoding, float sampleRate, int sampleSizeInBits,
179                         int channels, int frameSize, float frameRate,
180                         boolean bigEndian, Map<String, Object> properties)
181      {
182        this.encoding = encoding;
183        this.sampleRate = sampleRate;
184        this.sampleSizeInBits = sampleSizeInBits;
185        this.channels = channels;
186        this.frameSize = frameSize;
187        this.frameRate = frameRate;
188        this.bigEndian = bigEndian;
189        this.properties = Collections.unmodifiableMap(new HashMap<String, Object>(properties));
190      }
191    
192      /**
193       * Create a new PCM-based audio format, given various attributes of it.
194       * The encoding will either be Encoding#PCM_SIGNED or Encoding#PCM_UNSIGNED.
195       * The frame size for this format will be derived from the sample size in
196       * bits and the number of channels, unless one of those is
197       * AudioSystem#NOT_SPECIFIED.  The frame rate will be the same as the sample
198       * rate, and the properties map will be empty.
199       * 
200       * @param sampleRate the sample rate
201       * @param sampleSizeInBits the sample size, in bits
202       * @param channels the number of channels
203       * @param signed true if this is a signed encoding
204       * @param bigEndian true if the data is stored big-endian
205       */
206      public AudioFormat(float sampleRate, int sampleSizeInBits,
207                         int channels, boolean signed, boolean bigEndian)
208      {
209        this.encoding = signed ? Encoding.PCM_SIGNED : Encoding.PCM_UNSIGNED;
210        this.sampleRate = sampleRate;
211        this.sampleSizeInBits = sampleSizeInBits;
212        this.channels = channels;
213        // It isn't clear whether channels can be NOT_SPECIFIED.
214        if (sampleSizeInBits == AudioSystem.NOT_SPECIFIED
215            || channels == AudioSystem.NOT_SPECIFIED)
216          this.frameSize = AudioSystem.NOT_SPECIFIED;
217        else
218          this.frameSize = (sampleSizeInBits + 7) / 8 * channels;
219        this.frameRate = sampleRate;
220        this.bigEndian = bigEndian;
221        this.properties = Collections.<String, Object> emptyMap();
222      }
223    
224      /**
225       * Return the number of channels in this format.
226       */
227      public int getChannels()
228      {
229        return channels;
230      }
231    
232      /**
233       * Return the encoding of this format.
234       */
235      public Encoding getEncoding()
236      {
237        return encoding;
238      }
239    
240      /**
241       * Return the frame rate of this format.
242       */
243      public float getFrameRate()
244      {
245        return frameRate;
246      }
247    
248      /**
249       * Return the frame size of this format.
250       */
251      public int getFrameSize()
252      {
253        return frameSize;
254      }
255    
256      /**
257       * Given a key, return a property associated with this format;
258       * or null if this property is not set. 
259       * @param key the name of the property
260       * @return the value of the property, or null if the property is not set
261       */
262      public Object getProperty(String key)
263      {
264        return properties.get(key);
265      }
266    
267      /**
268       * Return the sample rate of this format.
269       */
270      public float getSampleRate()
271      {
272        return sampleRate;
273      }
274    
275      /**
276       * Return the sample size of this format, in bits.
277       */
278      public int getSampleSizeInBits()
279      {
280        return sampleSizeInBits;
281      }
282    
283      /**
284       * Return true if this format is big endian, false otherwise.
285       * This only matters for formats whose sample size is greater than
286       * one byte.
287       */
288      public boolean isBigEndian()
289      {
290        return bigEndian;
291      }
292    
293      /**
294       * Return true if this audio format matches another.
295       * @param fmt the format to match against
296       * @return true if they match, false otherwise
297       */
298      public boolean matches(AudioFormat fmt)
299      {
300        if (! encoding.equals(fmt.encoding)
301            || channels != fmt.channels
302            || sampleSizeInBits != fmt.sampleSizeInBits
303            || frameSize != fmt.frameSize)
304          return false;
305        if (sampleRate != AudioSystem.NOT_SPECIFIED
306            && fmt.sampleRate != AudioSystem.NOT_SPECIFIED
307            && sampleRate != fmt.sampleRate)
308          return false;
309        if (frameRate != AudioSystem.NOT_SPECIFIED
310            && fmt.frameRate != AudioSystem.NOT_SPECIFIED
311            && frameRate != fmt.frameRate)
312          return false;
313        if (sampleSizeInBits > 8)
314          return bigEndian == fmt.bigEndian;
315        return true;
316      }
317    
318      /**
319       * Return a read-only Map holding the properties associated with 
320       * this format.
321       */
322      public Map<String, Object> properties()
323      {
324        return properties;
325      }
326    
327      /**
328       * Return a description of this format.
329       */
330      public String toString()
331      {
332        StringBuffer result = new StringBuffer();
333        
334        // usually at least encoding should be somewhat specified
335        result.append(encoding);
336        
337        if (sampleRate != AudioSystem.NOT_SPECIFIED)
338          {
339            result.append(" ");
340            result.append(sampleRate);
341            result.append(" Hz");
342          }
343        
344        if (sampleSizeInBits != AudioSystem.NOT_SPECIFIED)
345          {
346            result.append(" ");
347            result.append(sampleSizeInBits);
348            result.append(" bits");
349          }
350        
351        if (channels != AudioSystem.NOT_SPECIFIED)
352          {
353            result.append(" ");
354            result.append(channels);
355            result.append(" channel");
356            if (channels > 1) result.append("s");
357          }
358        
359        if (sampleSizeInBits > 8)
360          result.append(bigEndian ? " big endian" : " little endian");
361        
362        return result.toString();
363      }
364    }