/* * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.sound.sampled; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * {@code AudioFormat} is the class that specifies a particular arrangement of * data in a sound stream. By examining the information stored in the audio * format, you can discover how to interpret the bits in the binary sound data. *
* Every data line has an audio format associated with its data stream. The * audio format of a source (playback) data line indicates what kind of data the * data line expects to receive for output. For a target (capture) data line, * the audio format specifies the kind of the data that can be read from the * line. * Sound files also have audio formats, of course. The {@link AudioFileFormat} * class encapsulates an {@code AudioFormat} in addition to other, file-specific * information. Similarly, an {@link AudioInputStream} has an * {@code AudioFormat}. *
* The {@code AudioFormat} class accommodates a number of common sound-file * encoding techniques, including pulse-code modulation (PCM), mu-law encoding, * and a-law encoding. These encoding techniques are predefined, but service * providers can create new encoding types. The encoding that a specific format * uses is named by its {@code encoding} field. *
* In addition to the encoding, the audio format includes other properties that * further specify the exact arrangement of the data. These include the number * of channels, sample rate, sample size, byte order, frame rate, and frame * size. Sounds may have different numbers of audio channels: one for mono, two * for stereo. The sample rate measures how many "snapshots" (samples) of the * sound pressure are taken per second, per channel. (If the sound is stereo * rather than mono, two samples are actually measured at each instant of time: * one for the left channel, and another for the right channel; however, the * sample rate still measures the number per channel, so the rate is the same * regardless of the number of channels. This is the standard use of the term.) * The sample size indicates how many bits are used to store each snapshot; 8 * and 16 are typical values. For 16-bit samples (or any other sample size * larger than a byte), byte order is important; the bytes in each sample are * arranged in either the "little-endian" or "big-endian" style. For encodings * like PCM, a frame consists of the set of samples for all channels at a given * point in time, and so the size of a frame (in bytes) is always equal to the * size of a sample (in bytes) times the number of channels. However, with some * other sorts of encodings a frame can contain a bundle of compressed data for * a whole series of samples, as well as additional, non-sample data. For such * encodings, the sample rate and sample size refer to the data after it is * decoded into PCM, and so they are completely different from the frame rate * and frame size. *
* An {@code AudioFormat} object can include a set of properties. A property is * a pair of key and value: the key is of type {@code String}, the associated * property value is an arbitrary object. Properties specify additional format * specifications, like the bit rate for compressed formats. Properties are * mainly used as a means to transport additional information of the audio * format to and from the service providers. Therefore, properties are ignored * in the {@link #matches(AudioFormat)} method. However, methods which rely on * the installed service providers, like * {@link AudioSystem#isConversionSupported (AudioFormat, AudioFormat) * isConversionSupported} may consider properties, depending on the respective * service provider implementation. *
* The following table lists some common properties which service providers * should use, if applicable: * *
Property key | *Value type | *Description | *
---|---|---|
"bitrate" | *{@link java.lang.Integer Integer} | *average bit rate in bits per second | *
"vbr" | *{@link java.lang.Boolean Boolean} | *{@code true}, if the file is encoded in variable bit * rate (VBR) | *
"quality" | *{@link java.lang.Integer Integer} | *encoding/conversion quality, 1..100 | *
* Vendors of service providers (plugins) are encouraged to seek information
* about other already established properties in third party plugins, and follow
* the same conventions.
*
* @author Kara Kytle
* @author Florian Bomers
* @see DataLine#getFormat
* @see AudioInputStream#getFormat
* @see AudioFileFormat
* @see javax.sound.sampled.spi.FormatConversionProvider
* @since 1.3
*/
public class AudioFormat {
/**
* The audio encoding technique used by this format.
*/
protected Encoding encoding;
/**
* The number of samples played or recorded per second, for sounds that have
* this format.
*/
protected float sampleRate;
/**
* The number of bits in each sample of a sound that has this format.
*/
protected int sampleSizeInBits;
/**
* The number of audio channels in this format (1 for mono, 2 for stereo).
*/
protected int channels;
/**
* The number of bytes in each frame of a sound that has this format.
*/
protected int frameSize;
/**
* The number of frames played or recorded per second, for sounds that have
* this format.
*/
protected float frameRate;
/**
* Indicates whether the audio data is stored in big-endian or little-endian
* order.
*/
protected boolean bigEndian;
/**
* The set of properties.
*/
private HashMap
* If the specified property is not defined for a particular file format,
* this method returns {@code null}.
*
* @param key the key of the desired property
* @return the value of the property with the specified key, or {@code null}
* if the property does not exist
* @see #properties()
* @since 1.5
*/
public Object getProperty(String key) {
if (properties == null) {
return null;
}
return properties.get(key);
}
/**
* Indicates whether this format matches the one specified. To match, two
* formats must have the same encoding, and consistent values of the number
* of channels, sample rate, sample size, frame rate, and frame size. The
* values of the property are consistent if they are equal or the specified
* format has the property value {@code AudioSystem.NOT_SPECIFIED}. The byte
* order (big-endian or little-endian) must be the same if the sample size
* is greater than one byte.
*
* @param format format to test for match
* @return {@code true} if this format matches the one specified,
* {@code false} otherwise
*/
public boolean matches(AudioFormat format) {
if (format.getEncoding().equals(getEncoding())
&& (format.getChannels() == AudioSystem.NOT_SPECIFIED
|| format.getChannels() == getChannels())
&& (format.getSampleRate() == (float)AudioSystem.NOT_SPECIFIED
|| format.getSampleRate() == getSampleRate())
&& (format.getSampleSizeInBits() == AudioSystem.NOT_SPECIFIED
|| format.getSampleSizeInBits() == getSampleSizeInBits())
&& (format.getFrameRate() == (float)AudioSystem.NOT_SPECIFIED
|| format.getFrameRate() == getFrameRate())
&& (format.getFrameSize() == AudioSystem.NOT_SPECIFIED
|| format.getFrameSize() == getFrameSize())
&& (getSampleSizeInBits() <= 8
|| format.isBigEndian() == isBigEndian())) {
return true;
}
return false;
}
/**
* Returns a string that describes the format, such as: "PCM SIGNED 22050 Hz
* 16 bit mono big-endian". The contents of the string may vary between
* implementations of Java Sound.
*
* @return a string that describes the format parameters
*/
@Override
public String toString() {
String sEncoding = "";
if (getEncoding() != null) {
sEncoding = getEncoding().toString() + " ";
}
String sSampleRate;
if (getSampleRate() == (float) AudioSystem.NOT_SPECIFIED) {
sSampleRate = "unknown sample rate, ";
} else {
sSampleRate = "" + getSampleRate() + " Hz, ";
}
String sSampleSizeInBits;
if (getSampleSizeInBits() == (float) AudioSystem.NOT_SPECIFIED) {
sSampleSizeInBits = "unknown bits per sample, ";
} else {
sSampleSizeInBits = "" + getSampleSizeInBits() + " bit, ";
}
String sChannels;
if (getChannels() == 1) {
sChannels = "mono, ";
} else
if (getChannels() == 2) {
sChannels = "stereo, ";
} else {
if (getChannels() == AudioSystem.NOT_SPECIFIED) {
sChannels = " unknown number of channels, ";
} else {
sChannels = ""+getChannels()+" channels, ";
}
}
String sFrameSize;
if (getFrameSize() == (float) AudioSystem.NOT_SPECIFIED) {
sFrameSize = "unknown frame size, ";
} else {
sFrameSize = "" + getFrameSize()+ " bytes/frame, ";
}
String sFrameRate = "";
if (Math.abs(getSampleRate() - getFrameRate()) > 0.00001) {
if (getFrameRate() == (float) AudioSystem.NOT_SPECIFIED) {
sFrameRate = "unknown frame rate, ";
} else {
sFrameRate = getFrameRate() + " frames/second, ";
}
}
String sEndian = "";
if ((getEncoding().equals(Encoding.PCM_SIGNED)
|| getEncoding().equals(Encoding.PCM_UNSIGNED))
&& ((getSampleSizeInBits() > 8)
|| (getSampleSizeInBits() == AudioSystem.NOT_SPECIFIED))) {
if (isBigEndian()) {
sEndian = "big-endian";
} else {
sEndian = "little-endian";
}
}
return sEncoding
+ sSampleRate
+ sSampleSizeInBits
+ sChannels
+ sFrameSize
+ sFrameRate
+ sEndian;
}
/**
* The {@code Encoding} class names the specific type of data representation
* used for an audio stream. The encoding includes aspects of the sound
* format other than the number of channels, sample rate, sample size, frame
* rate, frame size, and byte order.
*
* One ubiquitous type of audio encoding is pulse-code modulation (PCM),
* which is simply a linear (proportional) representation of the sound
* waveform. With PCM, the number stored in each sample is proportional to
* the instantaneous amplitude of the sound pressure at that point in time.
* The numbers may be signed or unsigned integers or floats. Besides PCM,
* other encodings include mu-law and a-law, which are nonlinear mappings of
* the sound amplitude that are often used for recording speech.
*
* You can use a predefined encoding by referring to one of the static
* objects created by this class, such as PCM_SIGNED or PCM_UNSIGNED.
* Service providers can create new encodings, such as compressed audio
* formats, and make these available through the {@link AudioSystem} class.
*
* The {@code Encoding} class is static, so that all {@code AudioFormat}
* objects that have the same encoding will refer to the same object (rather
* than different instances of the same class). This allows matches to be
* made by checking that two format's encodings are equal.
*
* @author Kara Kytle
* @see AudioFormat
* @see javax.sound.sampled.spi.FormatConversionProvider
* @since 1.3
*/
public static class Encoding {
/**
* Specifies signed, linear PCM data.
*/
public static final Encoding PCM_SIGNED = new Encoding("PCM_SIGNED");
/**
* Specifies unsigned, linear PCM data.
*/
public static final Encoding PCM_UNSIGNED = new Encoding("PCM_UNSIGNED");
/**
* Specifies floating-point PCM data.
*
* @since 1.7
*/
public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT");
/**
* Specifies u-law encoded data.
*/
public static final Encoding ULAW = new Encoding("ULAW");
/**
* Specifies a-law encoded data.
*/
public static final Encoding ALAW = new Encoding("ALAW");
/**
* Encoding name.
*/
private final String name;
/**
* Constructs a new encoding.
*
* @param name the name of the new type of encoding
*/
public Encoding(final String name) {
this.name = name;
}
/**
* Finalizes the equals method.
*/
@Override
public final boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Encoding)) {
return false;
}
return Objects.equals(name, ((Encoding) obj).name);
}
/**
* Finalizes the hashCode method.
*/
@Override
public final int hashCode() {
return name != null ? name.hashCode() : 0;
}
/**
* Provides the {@code String} representation of the encoding. This
* {@code String} is the same name that was passed to the constructor.
* For the predefined encodings, the name is similar to the encoding's
* variable (field) name. For example, {@code PCM_SIGNED.toString()}
* returns the name "PCM_SIGNED".
*
* @return the encoding name
*/
@Override
public final String toString() {
return name;
}
}
}