All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javazoom.jl.decoder.MP3Decoder Maven / Gradle / Ivy

/*
 * 11/19/04 1.0 moved to LGPL. 01/12/99 Initial version. [email protected]
 * ----------------------------------------------------------------------- This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This program 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 Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 * ----------------------------------------------------------------------
 */

package javazoom.jl.decoder;


/**
 * The Decoder class encapsulates the details of decoding an MPEG audio frame.
 * 
 * @author MDM
 * @version 0.0.7 12/12/99
 * @since 0.0.5
 */
public class MP3Decoder {
	/**
	 * The Bistream from which the MPEG audio frames are read.
	 */
	// private Bitstream stream;
	/**
	 * The Obuffer instance that will receive the decoded PCM samples.
	 */
	private OutputBuffer output;

	/**
	 * Synthesis filter for the left channel.
	 */
	private SynthesisFilter filter1;

	/**
	 * Sythesis filter for the right channel.
	 */
	private SynthesisFilter filter2;

	private LayerIIIDecoder l3decoder;
	private LayerIIDecoder l2decoder;
	private LayerIDecoder l1decoder;

	private int outputFrequency;
	private int outputChannels;

	private boolean initialized;

	/**
	 * Creates a new Decoder instance with default parameters.
	 */

	public MP3Decoder () {
	}

	/**
	 * Decodes one frame from an MPEG audio bitstream.
	 * 
	 * @param header The header describing the frame to decode.
	 * @param bitstream The bistream that provides the bits for te body of the frame.
	 * 
	 * @return A SampleBuffer containing the decoded samples.
	 */
	public OutputBuffer decodeFrame (Header header, Bitstream stream) throws DecoderException {
		if (!initialized) initialize(header);

		int layer = header.layer();

		FrameDecoder decoder = retrieveDecoder(header, stream, layer);

		decoder.decodeFrame();

		return output;
	}

	/**
	 * Changes the output buffer. This will take effect the next time decodeFrame() is called.
	 */
	public void setOutputBuffer (OutputBuffer out) {
		output = out;
	}

	/**
	 * Retrieves the sample frequency of the PCM samples output by this decoder. This typically corresponds to the sample rate
	 * encoded in the MPEG audio stream.
	 * 
	 * @param the sample rate (in Hz) of the samples written to the output buffer when decoding.
	 */
	public int getOutputFrequency () {
		return outputFrequency;
	}

	/**
	 * Retrieves the number of channels of PCM samples output by this decoder. This usually corresponds to the number of channels
	 * in the MPEG audio stream, although it may differ.
	 * 
	 * @return The number of output channels in the decoded samples: 1 for mono, or 2 for stereo.
	 * 
	 */
	public int getOutputChannels () {
		return outputChannels;
	}

	protected DecoderException newDecoderException (int errorcode) {
		return new DecoderException(errorcode, null);
	}

	protected DecoderException newDecoderException (int errorcode, Throwable throwable) {
		return new DecoderException(errorcode, throwable);
	}

	protected FrameDecoder retrieveDecoder (Header header, Bitstream stream, int layer) throws DecoderException {
		FrameDecoder decoder = null;

		// REVIEW: allow channel output selection type
		// (LEFT, RIGHT, BOTH, DOWNMIX)
		switch (layer) {
		case 3:
			if (l3decoder == null)
				l3decoder = new LayerIIIDecoder(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);

			decoder = l3decoder;
			break;
		case 2:
			if (l2decoder == null) {
				l2decoder = new LayerIIDecoder();
				l2decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);
			}
			decoder = l2decoder;
			break;
		case 1:
			if (l1decoder == null) {
				l1decoder = new LayerIDecoder();
				l1decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);
			}
			decoder = l1decoder;
			break;
		}

		if (decoder == null) throw newDecoderException(UNSUPPORTED_LAYER, null);

		return decoder;
	}

	private void initialize (Header header) throws DecoderException {

		// REVIEW: allow customizable scale factor
		float scalefactor = 32700.0f;

		int mode = header.mode();
		header.layer();
		int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;

		// set up output buffer if not set up by client.
		if (output == null) throw new RuntimeException("Output buffer was not set.");

		filter1 = new SynthesisFilter(0, scalefactor, null);

		// REVIEW: allow mono output for stereo
		if (channels == 2) filter2 = new SynthesisFilter(1, scalefactor, null);

		outputChannels = channels;
		outputFrequency = header.frequency();

		initialized = true;
	}

	/**
	 * The first decoder error code. See the {@link DecoderErrors DecoderErrors} interface for other decoder error codes.
	 */
	static public final int DECODER_ERROR = 0x200;

	static public final int UNKNOWN_ERROR = DECODER_ERROR + 0;

	/**
	 * Layer not supported by the decoder.
	 */
	static public final int UNSUPPORTED_LAYER = DECODER_ERROR + 1;

	/**
	 * Illegal allocation in subband layer. Indicates a corrupt stream.
	 */
	static public final int ILLEGAL_SUBBAND_ALLOCATION = DECODER_ERROR + 2;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy