2 * 11/19/04 1.0 moved to LGPL.
\r
3 * 01/12/99 Initial version. mdm@techie.com
\r
4 *-----------------------------------------------------------------------
\r
5 * This program is free software; you can redistribute it and/or modify
\r
6 * it under the terms of the GNU Library General Public License as published
\r
7 * by the Free Software Foundation; either version 2 of the License, or
\r
8 * (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU Library General Public License for more details.
\r
15 * You should have received a copy of the GNU Library General Public
\r
16 * License along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
18 *----------------------------------------------------------------------
\r
22 * The <code>Decoder</code> class encapsulates the details of decoding an MPEG
\r
26 * @version 0.0.7 12/12/99
\r
29 @LATTICE("ST,DE<OUT,DE<FIL,DE<LA,O,EQ,PA,INIT,DE*")
\r
30 public class Decoder implements DecoderErrors {
\r
31 static private final Params DEFAULT_PARAMS = new Params();
\r
34 * The Bistream from which the MPEG audio frames are read.
\r
37 private Bitstream stream;
\r
40 * The Obuffer instance that will receive the decoded PCM samples.
\r
43 private Obuffer output;
\r
46 * Synthesis filter for the left channel.
\r
49 private SynthesisFilter filter1;
\r
52 * Sythesis filter for the right channel.
\r
55 private SynthesisFilter filter2;
\r
58 * The decoder used to decode layer III frames.
\r
61 private LayerIIIDecoder l3decoder;
\r
63 // private LayerIIDecoder l2decoder;
\r
65 // private LayerIDecoder l1decoder;
\r
68 private int outputFrequency;
\r
70 private int outputChannels;
\r
73 private Equalizer equalizer = new Equalizer();
\r
76 private Params params;
\r
79 private boolean initialized;
\r
82 * Creates a new <code>Decoder</code> instance with default parameters.
\r
90 * Creates a new <code>Decoder</code> instance with default parameters.
\r
93 * The <code>Params</code> instance that describes the customizable
\r
94 * aspects of the decoder.
\r
96 public Decoder(Params params0) {
\r
97 if (params0 == null)
\r
98 params0 = DEFAULT_PARAMS;
\r
102 Equalizer eq = params.getInitialEqualizerSettings();
\r
104 equalizer.setFrom(eq);
\r
108 static public Params getDefaultParams() {
\r
109 return (Params) DEFAULT_PARAMS.clone();
\r
112 public void setEqualizer(Equalizer eq) {
\r
114 eq = Equalizer.PASS_THRU_EQ;
\r
116 equalizer.setFrom(eq);
\r
118 float[] factors = equalizer.getBandFactors();
\r
120 if (filter1 != null)
\r
121 filter1.setEQ(factors);
\r
123 if (filter2 != null)
\r
124 filter2.setEQ(factors);
\r
128 * Decodes one frame from an MPEG audio bitstream.
\r
131 * The header describing the frame to decode.
\r
133 * The bistream that provides the bits for te body of the frame.
\r
135 * @return A SampleBuffer containing the decoded samples.
\r
137 @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")
\r
139 public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)
\r
140 throws DecoderException {
\r
142 if (!initialized) {
\r
143 initialize(header);
\r
146 @LOC("TH") int layer = header.layer();
\r
148 output.clear_buffer();
\r
150 @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return
\r
152 decoder.decodeFrame();
\r
154 // if (layer == 3) {
\r
155 // if (l3decoder == null) {
\r
157 // new LayerIIIDecoder(stream, header, filter1, filter2, output,
\r
158 // OutputChannels.BOTH_CHANNELS);
\r
160 // l3decoder.decodeFrame();
\r
161 // } else if (layer == 2) {
\r
162 // if (l2decoder == null) {
\r
163 // l2decoder = new LayerIIDecoder();
\r
164 // l2decoder.create(stream, header, filter1, filter2, output,
\r
165 // OutputChannels.BOTH_CHANNELS);
\r
167 // l2decoder.decodeFrame();
\r
169 // if (l1decoder == null) {
\r
170 // l1decoder = new LayerIDecoder();
\r
171 // l1decoder.create(stream, header, filter1, filter2, output,
\r
172 // OutputChannels.BOTH_CHANNELS);
\r
174 // l1decoder.decodeFrame();
\r
177 output.write_buffer(1);
\r
183 * Changes the output buffer. This will take effect the next time
\r
184 * decodeFrame() is called.
\r
186 public void setOutputBuffer(Obuffer out) {
\r
191 * Retrieves the sample frequency of the PCM samples output by this decoder.
\r
192 * This typically corresponds to the sample rate encoded in the MPEG audio
\r
196 * sample rate (in Hz) of the samples written to the output buffer
\r
199 public int getOutputFrequency() {
\r
200 return outputFrequency;
\r
204 * Retrieves the number of channels of PCM samples output by this decoder.
\r
205 * This usually corresponds to the number of channels in the MPEG audio
\r
206 * stream, although it may differ.
\r
208 * @return The number of output channels in the decoded samples: 1 for mono,
\r
212 public int getOutputChannels() {
\r
213 return outputChannels;
\r
217 * Retrieves the maximum number of samples that will be written to the output
\r
218 * buffer when one frame is decoded. This can be used to help calculate the
\r
219 * size of other buffers whose size is based upon the number of samples
\r
220 * written to the output buffer. NB: this is an upper bound and fewer samples
\r
221 * may actually be written, depending upon the sample rate and number of
\r
224 * @return The maximum number of samples that are written to the output buffer
\r
225 * when decoding a single frame of MPEG audio.
\r
227 public int getOutputBlockSize() {
\r
228 return Obuffer.OBUFFERSIZE;
\r
231 protected DecoderException newDecoderException(int errorcode) {
\r
232 return new DecoderException(errorcode, null);
\r
235 protected DecoderException newDecoderException(int errorcode, Throwable throwable) {
\r
236 return new DecoderException(errorcode, throwable);
\r
239 @LATTICE("IN,TH,THISLOC=TH")
\r
241 protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream,
\r
242 @LOC("IN") int layer) throws DecoderException {
\r
243 // @LOC("DE") FrameDecoder decoder = null;
\r
245 // REVIEW: allow channel output selection type
\r
246 // (LEFT, RIGHT, BOTH, DOWNMIX)
\r
249 if (l3decoder == null) {
\r
251 new LayerIIIDecoder(header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);
\r
255 // decoder = l3decoder;
\r
258 // if (l2decoder == null) {
\r
259 // l2decoder = new LayerIIDecoder();
\r
260 // l2decoder.create(stream, header, filter1, filter2, output,
\r
261 // OutputChannels.BOTH_CHANNELS);
\r
263 // return l2decoder;
\r
264 // // decoder = l2decoder;
\r
267 // if (l1decoder == null) {
\r
268 // l1decoder = new LayerIDecoder();
\r
269 // l1decoder.create(stream, header, filter1, filter2, output,
\r
270 // OutputChannels.BOTH_CHANNELS);
\r
272 // return l1decoder;
\r
273 // // decoder = l1decoder;
\r
277 // if (decoder==null)
\r
279 // throw newDecoderException(UNSUPPORTED_LAYER, null);
\r
285 public void initialize(Header header) throws DecoderException {
\r
287 // REVIEW: allow customizable scale factor
\r
288 float scalefactor = 32700.0f;
\r
290 int mode = header.mode();
\r
291 int layer = header.layer();
\r
292 int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;
\r
294 // set up output buffer if not set up by client.
\r
295 if (output == null)
\r
296 output = new SampleBuffer(header.frequency(), channels);
\r
298 float[] factors = equalizer.getBandFactors();
\r
299 filter1 = new SynthesisFilter(0, scalefactor, factors);
\r
301 // REVIEW: allow mono output for stereo
\r
303 filter2 = new SynthesisFilter(1, scalefactor, factors);
\r
305 outputChannels = channels;
\r
306 outputFrequency = header.frequency();
\r
308 initialized = true;
\r
312 * The <code>Params</code> class presents the customizable aspects of the
\r
315 * Instances of this class are not thread safe.
\r
317 public static class Params implements Cloneable {
\r
318 private OutputChannels outputChannels = OutputChannels.BOTH;
\r
320 private Equalizer equalizer = new Equalizer();
\r
325 public Object clone() {
\r
326 // TODO: need to have better clone method
\r
327 Params clone = new Params();
\r
328 clone.outputChannels = outputChannels;
\r
329 clone.equalizer = equalizer;
\r
333 // return super.clone();
\r
335 // catch (CloneNotSupportedException ex)
\r
337 // throw new InternalError(this+": "+ex);
\r
341 public void setOutputChannels(OutputChannels out) {
\r
343 throw new NullPointerException("out");
\r
345 outputChannels = out;
\r
348 public OutputChannels getOutputChannels() {
\r
349 return outputChannels;
\r
353 * Retrieves the equalizer settings that the decoder's equalizer will be
\r
354 * initialized from.
\r
356 * The <code>Equalizer</code> instance returned cannot be changed in real
\r
357 * time to affect the decoder output as it is used only to initialize the
\r
358 * decoders EQ settings. To affect the decoder's output in realtime, use the
\r
359 * Equalizer returned from the getEqualizer() method on the decoder.
\r
361 * @return The <code>Equalizer</code> used to initialize the EQ settings of
\r
364 public Equalizer getInitialEqualizerSettings() {
\r