/*
* 11/19/04 1.0 moved to LGPL.
* 01/12/99 Initial version. mdm@techie.com
*-----------------------------------------------------------------------
* 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.
*----------------------------------------------------------------------
*/
/**
* 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 Decoder implements DecoderErrors {
static private final Params DEFAULT_PARAMS = new Params();
/**
* The Bistream from which the MPEG audio frames are read.
*/
//
// private Bitstream stream;
/**
* The Obuffer instance that will receive the decoded PCM samples.
*/
//
// private Obuffer output;
/**
* Synthesis filter for the left channel.
*/
//
// private SynthesisFilter filter1;
/**
* Sythesis filter for the right channel.
*/
//
// private SynthesisFilter filter2;
/**
* The decoder used to decode layer III frames.
*/
private LayerIIIDecoder l3decoder;
//
// private LayerIIDecoder l2decoder;
//
// private LayerIDecoder l1decoder;
private int outputFrequency;
private int outputChannels;
private Equalizer equalizer = new Equalizer();
private Params params;
private boolean initialized;
/**
* Creates a new Decoder
instance with default parameters.
*/
public Decoder() {
this(null);
}
/**
* Creates a new Decoder
instance with default parameters.
*
* @param params
* The Params
instance that describes the customizable
* aspects of the decoder.
*/
public Decoder(@DELEGATE Params params0) {
if (params0 == null) {
params0 = getDefaultParams();
}
params = params0;
Equalizer eq = params.getInitialEqualizerSettings();
if (eq != null) {
equalizer.setFrom(eq);
}
}
static public Params getDefaultParams() {
return (Params) DEFAULT_PARAMS.clone();
}
// public void setEqualizer(Equalizer eq) {
// if (eq == null)
// eq = Equalizer.PASS_THRU_EQ;
//
// equalizer.setFrom(eq);
//
// float[] factors = equalizer.getBandFactors();
//
// if (filter1 != null)
// filter1.setEQ(factors);
//
// if (filter2 != null)
// filter2.setEQ(factors);
// }
public void init(Header header) {
float scalefactor = 32700.0f;
int mode = header.mode();
int layer = header.layer();
int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;
// set up output buffer if not set up by client.
// if (output == null)
// output = new SampleBuffer(header.frequency(), channels);
SampleBufferWrapper.init(header.frequency(), channels);
float[] factors = equalizer.getBandFactors();
SynthesisFilter filter1 = new SynthesisFilter(0, scalefactor, factors);
// REVIEW: allow mono output for stereo
SynthesisFilter filter2 = null;
if (channels == 2) {
filter2 = new SynthesisFilter(1, scalefactor, factors);
}
outputChannels = channels;
outputFrequency = header.frequency();
l3decoder = new LayerIIIDecoder(header, filter1, filter2, OutputChannels.BOTH_CHANNELS);
}
/**
* 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 void decodeFrame(Header header) throws DecoderException {
SampleBufferWrapper.clear_buffer();
l3decoder.decode(header);
// SampleBufferWrapper.getOutput().write_buffer(1);
}
/**
* Changes the output buffer. This will take effect the next time
* decodeFrame() is called.
*/
// public void setOutputBuffer(Obuffer 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;
}
/**
* Retrieves the maximum number of samples that will be written to the output
* buffer when one frame is decoded. This can be used to help calculate the
* size of other buffers whose size is based upon the number of samples
* written to the output buffer. NB: this is an upper bound and fewer samples
* may actually be written, depending upon the sample rate and number of
* channels.
*
* @return The maximum number of samples that are written to the output buffer
* when decoding a single frame of MPEG audio.
*/
public int getOutputBlockSize() {
return Obuffer.OBUFFERSIZE;
}
protected DecoderException newDecoderException(int errorcode) {
return new DecoderException(errorcode, null);
}
protected DecoderException newDecoderException(int errorcode, Throwable throwable) {
return new DecoderException(errorcode, throwable);
}
}
/**
* The Params
class presents the customizable aspects of the
* decoder.
*
* Instances of this class are not thread safe. */ public class Params implements Cloneable { // private OutputChannels outputChannels = OutputChannels.BOTH; private OutputChannels outputChannels = new OutputChannels(0); private Equalizer equalizer = new Equalizer(); public Params() { } public Object clone() { // TODO: need to have better clone method Params clone = new Params(); clone.outputChannels = new OutputChannels(outputChannels.getChannelsOutputCode()); clone.equalizer = new Equalizer(); return clone; // try // { // return super.clone(); // } // catch (CloneNotSupportedException ex) // { // throw new InternalError(this+": "+ex); // } } public void setOutputChannels(OutputChannels out) { if (out == null) throw new NullPointerException("out"); outputChannels = out; } public OutputChannels getOutputChannels() { return outputChannels; } /** * Retrieves the equalizer settings that the decoder's equalizer will be * initialized from. *
* The Equalizer
instance returned cannot be changed in real time
* to affect the decoder output as it is used only to initialize the decoders
* EQ settings. To affect the decoder's output in realtime, use the Equalizer
* returned from the getEqualizer() method on the decoder.
*
* @return The Equalizer
used to initialize the EQ settings of
* the decoder.
*/
public Equalizer getInitialEqualizerSettings() {
return equalizer;
}
}