// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer 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 for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.
package net.avadeaux.klipspringer.codec;
import java.nio.ByteOrder;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
/** Audio format specification that extends {@link AudioFormat} with some convenience functions and
* restrictions. The sample size (frame size divided by number of channels) must be 1 or 2 for bit
* depth 8 or smaller, 2 for bit depth 9 to 16, 3 or 4 for bit depth 17 to 24, and 4 for bit depth
* 25 to 32. Bit depth larger than 32 is not allowed. Attempting to construct a PCM format that
* does not conform to these rules results in exception. The additional field for significant bits
* per sample should normally be equal to bits per sample, but may be smaller if the bit depth has
* been scaled up by left shifting, in which case the significant number of bits should be
* displayed as the actual quality.
*/
public class PcmFormat extends AudioFormat {
/** Interface for selecting a quality-compatible audio format. */
public interface Selector {
/** Gets a supported format that matches the parameter in quality (sample rate, bit depth,
* and number of channels). If possible, frame size, signedness and endianness of the
* parameter are also matched.
*
* @throws UnsupportedFormatException if no quality-matching format is supported.
*/
PcmFormat selectFormat(AudioFormat format) throws UnsupportedFormatException;
}
/** Maximum accepted frame size. */
public final static int MAX_FS = 8 * 4;
/** The number of significant bytes for quick access. */
final int byps;
/** The number of bytes allocated per buffer, for quick access. */
final int ss;
/** The number of significant bits per sample. */
final int significantBips;
/** Constructor that specifies all fields. */
public PcmFormat(int rate, int bips, int channels, boolean signed, int fs, ByteOrder order, int significantBips) {
super(signed ? AudioFormat.Encoding.PCM_SIGNED : AudioFormat.Encoding.PCM_UNSIGNED, rate, bips, channels, fs, rate, order == ByteOrder.BIG_ENDIAN);
if (fs > MAX_FS) { throw new IllegalArgumentException("Frame size too large: "+fs); }
byps = (bips+7)/8;
ss = fs / channels;
this.significantBips = significantBips;
if (bips < 1 || bips > 32 || byps != ss && !(byps == 1 && ss == 2 || byps == 3 && ss == 4 || significantBips < bips)) {
throw new IllegalArgumentException("Inconsistent PCM format ("+bips+"/"+fs+" "+channels+" channels)"
+ (significantBips == bips ? "" : " ["+significantBips+"]"));
}
}
/** Constructor that specifies sound quality and sets other parameters to standard values. */
public PcmFormat(int rate, int bips, int channels) {
this(rate, bips, channels, true, (bips+7)/8 * channels, ByteOrder.nativeOrder(), bips);
}
/** Same value as {@link #getSampleRate()} but cast to int. */
public int rate() { return (int) sampleRate; }
/** Bits per sample, alias for {@link #getSampleSizeInBits()}. */
public int bips() { return sampleSizeInBits; }
/** Significant bits per sample. Returns the same value as {@link #bips()} unless the sample
* values have been scaled up from a smaller bit depth, in which case this is the original bit
* depth.
*/
public int significantBips() { return significantBips; }
/** Bytes per sample, ceiling of {@link #bips()}/8. */
public int byps() { return byps; }
/** Desired byte-alignment for data of this format. The lowest set bit of {@link #byps()}. */
public int alignment() { return byps & -byps; }
/** Number of channels, alias for {@link #getChannels()}. */
public int channels() { return channels; }
/** Boolean alternative to {@link #getEncoding()}. */
public boolean signed() { return encoding == AudioFormat.Encoding.PCM_SIGNED; }
/** Number of bytes allocated per sample, fs divided by channels. */
public int ss() { return ss; }
/** Frame size, alias for {@link #getFrameSize()}. */
public int fs() { return frameSize; }
/** Is big-endian, alias for {@link #isBigEndian()}. */
public boolean bigend() { return bigEndian; }
/** {@link ByteOrder} alternative to {@link #bigend()}. */
public ByteOrder order() { return bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; }
/** Checks if formats match in sample rate, bits per channel, and number of channels. */
public boolean matchesQuality(PcmFormat that) {
return sampleRate == that.sampleRate
&& sampleSizeInBits == that.sampleSizeInBits
&& channels == that.channels;
}
/** Gets a PCM format specified by standard {@link AudioFormat}, with specified sample rate in
* case it is unspecified in the given format.
*/
public static PcmFormat of(AudioFormat format, int rate) throws UnsupportedFormatException {
if (format instanceof PcmFormat && format.getSampleRate() == rate) { return (PcmFormat) format; }
AudioFormat.Encoding enc = format.getEncoding();
if (enc != AudioFormat.Encoding.PCM_SIGNED && enc != AudioFormat.Encoding.PCM_UNSIGNED) {
throw new UnsupportedFormatException("Non-PCM format not supported: "+enc);
}
if (format.getSampleRate() != AudioSystem.NOT_SPECIFIED && format.getSampleRate() != rate) {
throw new IllegalArgumentException("Sample rate mismatch: "+format.getSampleRate()+", "+rate);
}
return new PcmFormat(rate,
format.getSampleSizeInBits(),
format.getChannels(),
enc == AudioFormat.Encoding.PCM_SIGNED,
format.getFrameSize(),
format.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN,
format instanceof PcmFormat ? ((PcmFormat) format).significantBips() : format.getSampleSizeInBits());
}
/** Gets a PCM format specified by standard {@link AudioFormat} */
public static PcmFormat of(AudioFormat format) throws UnsupportedFormatException {
return of(format, (int) format.getSampleRate());
}
}
Version: v4.3.2.2 (2026-05-16T17:03:34+02:00)
Raw file
Source code overview
Klipspringer home