Source for javax.sound.sampled.AudioFormat

   1: /* An audio format
   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.sampled;
  40: 
  41: import gnu.java.lang.CPStringBuilder;
  42: 
  43: import java.util.Collections;
  44: import java.util.HashMap;
  45: import java.util.Map;
  46: 
  47: /**
  48:  * This class describes an audio format, including its encoding,
  49:  * the number of channels, its frame rate, etc.
  50:  * @since 1.3
  51:  */
  52: public class AudioFormat
  53: {
  54:   /**
  55:    * This describes a given audio format encoding.
  56:    * @since 1.3
  57:    */
  58:   public static class Encoding
  59:   {
  60:     /** The ALAW encoding.  */
  61:     public static final Encoding ALAW = new Encoding("alaw");
  62: 
  63:     /** The signed PCM encoding.  */
  64:     public static final Encoding PCM_SIGNED = new Encoding("pcm_signed");
  65: 
  66:     /** The unsigned PCM encoding.  */
  67:     public static final Encoding PCM_UNSIGNED = new Encoding("pcm_unsigned");
  68: 
  69:     /** The ULAW encoding.  */
  70:     public static final Encoding ULAW = new Encoding("ulaw");
  71: 
  72:     private String name;
  73: 
  74:     /**
  75:      * Create a new encoding descriptor, given its name.
  76:      * @param name the name
  77:      */
  78:     public Encoding(String name)
  79:     {
  80:       this.name = name;
  81:     }
  82: 
  83:     public final boolean equals(Object o)
  84:     {
  85:       return super.equals(o);
  86:     }
  87: 
  88:     public final int hashCode()
  89:     {
  90:       return super.hashCode();
  91:     }
  92: 
  93:     /**
  94:      * Return the name of this encoding.
  95:      */
  96:     public final String toString()
  97:     {
  98:       return name;
  99:     }
 100:   }
 101: 
 102:   /**
 103:    * True if the audio data is stored big-endian.
 104:    */
 105:   protected boolean bigEndian;
 106: 
 107:   /**
 108:    * The number of channels of data in this format.
 109:    */
 110:   protected int channels;
 111: 
 112:   /**
 113:    * The encoding of this format.
 114:    */
 115:   protected Encoding encoding;
 116: 
 117:   /**
 118:    * The frame rate of this format.  This is the number of frames
 119:    * per second.
 120:    */
 121:   protected float frameRate;
 122: 
 123:   /**
 124:    * The number of bytes per frame in this format.
 125:    */
 126:   protected int frameSize;
 127: 
 128:   /**
 129:    * The number of samples per second.
 130:    */
 131:   protected float sampleRate;
 132: 
 133:   /**
 134:    * The number of bits in each sample.
 135:    */
 136:   protected int sampleSizeInBits;
 137: 
 138:   private Map<String, Object> properties;
 139: 
 140:   /**
 141:    * Create a new audio format, given various attributes of it.
 142:    * The properties map for this format will be empty.
 143:    *
 144:    * @param encoding the encoding for this format
 145:    * @param sampleRate the sample rate
 146:    * @param sampleSizeInBits the sample size, in bits
 147:    * @param channels the number of channels
 148:    * @param frameSize the frame size, in bytes
 149:    * @param frameRate the frame rate, in frames per second
 150:    * @param bigEndian true if the data is stored big-endian
 151:    */
 152:   public AudioFormat(Encoding encoding, float sampleRate, int sampleSizeInBits,
 153:                      int channels, int frameSize, float frameRate,
 154:                      boolean bigEndian)
 155:   {
 156:     this.encoding = encoding;
 157:     this.sampleRate = sampleRate;
 158:     this.sampleSizeInBits = sampleSizeInBits;
 159:     this.channels = channels;
 160:     this.frameSize = frameSize;
 161:     this.frameRate = frameRate;
 162:     this.bigEndian = bigEndian;
 163:     this.properties = Collections.<String, Object> emptyMap();
 164:   }
 165: 
 166:   /**
 167:    * Create a new audio format, given various attributes of it.
 168:    * The properties map is copied by this constructor, so changes
 169:    * to the argument Map will not affect the new object.
 170:    *
 171:    * @param encoding the encoding for this format
 172:    * @param sampleRate the sample rate
 173:    * @param sampleSizeInBits the sample size, in bits
 174:    * @param channels the number of channels
 175:    * @param frameSize the frame size, in bytes
 176:    * @param frameRate the frame rate, in frames per second
 177:    * @param bigEndian true if the data is stored big-endian
 178:    * @param properties a map describing properties of this format
 179:    */
 180:   public AudioFormat(Encoding encoding, float sampleRate, int sampleSizeInBits,
 181:                      int channels, int frameSize, float frameRate,
 182:                      boolean bigEndian, Map<String, Object> properties)
 183:   {
 184:     this.encoding = encoding;
 185:     this.sampleRate = sampleRate;
 186:     this.sampleSizeInBits = sampleSizeInBits;
 187:     this.channels = channels;
 188:     this.frameSize = frameSize;
 189:     this.frameRate = frameRate;
 190:     this.bigEndian = bigEndian;
 191:     this.properties = Collections.unmodifiableMap(new HashMap<String, Object>(properties));
 192:   }
 193: 
 194:   /**
 195:    * Create a new PCM-based audio format, given various attributes of it.
 196:    * The encoding will either be Encoding#PCM_SIGNED or Encoding#PCM_UNSIGNED.
 197:    * The frame size for this format will be derived from the sample size in
 198:    * bits and the number of channels, unless one of those is
 199:    * AudioSystem#NOT_SPECIFIED.  The frame rate will be the same as the sample
 200:    * rate, and the properties map will be empty.
 201:    *
 202:    * @param sampleRate the sample rate
 203:    * @param sampleSizeInBits the sample size, in bits
 204:    * @param channels the number of channels
 205:    * @param signed true if this is a signed encoding
 206:    * @param bigEndian true if the data is stored big-endian
 207:    */
 208:   public AudioFormat(float sampleRate, int sampleSizeInBits,
 209:                      int channels, boolean signed, boolean bigEndian)
 210:   {
 211:     this.encoding = signed ? Encoding.PCM_SIGNED : Encoding.PCM_UNSIGNED;
 212:     this.sampleRate = sampleRate;
 213:     this.sampleSizeInBits = sampleSizeInBits;
 214:     this.channels = channels;
 215:     // It isn't clear whether channels can be NOT_SPECIFIED.
 216:     if (sampleSizeInBits == AudioSystem.NOT_SPECIFIED
 217:         || channels == AudioSystem.NOT_SPECIFIED)
 218:       this.frameSize = AudioSystem.NOT_SPECIFIED;
 219:     else
 220:       this.frameSize = (sampleSizeInBits + 7) / 8 * channels;
 221:     this.frameRate = sampleRate;
 222:     this.bigEndian = bigEndian;
 223:     this.properties = Collections.<String, Object> emptyMap();
 224:   }
 225: 
 226:   /**
 227:    * Return the number of channels in this format.
 228:    */
 229:   public int getChannels()
 230:   {
 231:     return channels;
 232:   }
 233: 
 234:   /**
 235:    * Return the encoding of this format.
 236:    */
 237:   public Encoding getEncoding()
 238:   {
 239:     return encoding;
 240:   }
 241: 
 242:   /**
 243:    * Return the frame rate of this format.
 244:    */
 245:   public float getFrameRate()
 246:   {
 247:     return frameRate;
 248:   }
 249: 
 250:   /**
 251:    * Return the frame size of this format.
 252:    */
 253:   public int getFrameSize()
 254:   {
 255:     return frameSize;
 256:   }
 257: 
 258:   /**
 259:    * Given a key, return a property associated with this format;
 260:    * or null if this property is not set.
 261:    * @param key the name of the property
 262:    * @return the value of the property, or null if the property is not set
 263:    */
 264:   public Object getProperty(String key)
 265:   {
 266:     return properties.get(key);
 267:   }
 268: 
 269:   /**
 270:    * Return the sample rate of this format.
 271:    */
 272:   public float getSampleRate()
 273:   {
 274:     return sampleRate;
 275:   }
 276: 
 277:   /**
 278:    * Return the sample size of this format, in bits.
 279:    */
 280:   public int getSampleSizeInBits()
 281:   {
 282:     return sampleSizeInBits;
 283:   }
 284: 
 285:   /**
 286:    * Return true if this format is big endian, false otherwise.
 287:    * This only matters for formats whose sample size is greater than
 288:    * one byte.
 289:    */
 290:   public boolean isBigEndian()
 291:   {
 292:     return bigEndian;
 293:   }
 294: 
 295:   /**
 296:    * Return true if this audio format matches another.
 297:    * @param fmt the format to match against
 298:    * @return true if they match, false otherwise
 299:    */
 300:   public boolean matches(AudioFormat fmt)
 301:   {
 302:     if (! encoding.equals(fmt.encoding)
 303:         || channels != fmt.channels
 304:         || sampleSizeInBits != fmt.sampleSizeInBits
 305:         || frameSize != fmt.frameSize)
 306:       return false;
 307:     if (sampleRate != AudioSystem.NOT_SPECIFIED
 308:         && fmt.sampleRate != AudioSystem.NOT_SPECIFIED
 309:         && sampleRate != fmt.sampleRate)
 310:       return false;
 311:     if (frameRate != AudioSystem.NOT_SPECIFIED
 312:         && fmt.frameRate != AudioSystem.NOT_SPECIFIED
 313:         && frameRate != fmt.frameRate)
 314:       return false;
 315:     if (sampleSizeInBits > 8)
 316:       return bigEndian == fmt.bigEndian;
 317:     return true;
 318:   }
 319: 
 320:   /**
 321:    * Return a read-only Map holding the properties associated with
 322:    * this format.
 323:    */
 324:   public Map<String, Object> properties()
 325:   {
 326:     return properties;
 327:   }
 328: 
 329:   /**
 330:    * Return a description of this format.
 331:    */
 332:   public String toString()
 333:   {
 334:     CPStringBuilder result = new CPStringBuilder();
 335: 
 336:     // usually at least encoding should be somewhat specified
 337:     result.append(encoding);
 338: 
 339:     if (sampleRate != AudioSystem.NOT_SPECIFIED)
 340:       {
 341:         result.append(" ");
 342:         result.append(sampleRate);
 343:         result.append(" Hz");
 344:       }
 345: 
 346:     if (sampleSizeInBits != AudioSystem.NOT_SPECIFIED)
 347:       {
 348:         result.append(" ");
 349:         result.append(sampleSizeInBits);
 350:         result.append(" bits");
 351:       }
 352: 
 353:     if (channels != AudioSystem.NOT_SPECIFIED)
 354:       {
 355:         result.append(" ");
 356:         result.append(channels);
 357:         result.append(" channel");
 358:         if (channels > 1) result.append("s");
 359:       }
 360: 
 361:     if (sampleSizeInBits > 8)
 362:       result.append(bigEndian ? " big endian" : " little endian");
 363: 
 364:     return result.toString();
 365:   }
 366: }