get rid of the stream parsing that occurs in the Layer III decoder. BitStream.readFra...
[IRC.git] / Robust / src / Tests / ssJava / mp3decoder / Decoder.java
1 /*\r
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
9  *\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
14  *\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
19  */\r
20 \r
21 /**\r
22  * The <code>Decoder</code> class encapsulates the details of decoding an MPEG\r
23  * audio frame.\r
24  * \r
25  * @author MDM\r
26  * @version 0.0.7 12/12/99\r
27  * @since 0.0.5\r
28  */\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
32 \r
33   /**\r
34    * The Bistream from which the MPEG audio frames are read.\r
35    */\r
36   @LOC("ST")\r
37   private Bitstream stream;\r
38 \r
39   /**\r
40    * The Obuffer instance that will receive the decoded PCM samples.\r
41    */\r
42   @LOC("OUT")\r
43   private Obuffer output;\r
44 \r
45   /**\r
46    * Synthesis filter for the left channel.\r
47    */\r
48   @LOC("FIL")\r
49   private SynthesisFilter filter1;\r
50 \r
51   /**\r
52    * Sythesis filter for the right channel.\r
53    */\r
54   @LOC("FIL")\r
55   private SynthesisFilter filter2;\r
56 \r
57   /**\r
58    * The decoder used to decode layer III frames.\r
59    */\r
60   @LOC("DE")\r
61   private LayerIIIDecoder l3decoder;\r
62   @LOC("DE")\r
63   private LayerIIDecoder l2decoder;\r
64   @LOC("DE")\r
65   private LayerIDecoder l1decoder;\r
66 \r
67   @LOC("O")\r
68   private int outputFrequency;\r
69   @LOC("O")\r
70   private int outputChannels;\r
71 \r
72   @LOC("EQ")\r
73   private Equalizer equalizer = new Equalizer();\r
74 \r
75   @LOC("PA")\r
76   private Params params;\r
77 \r
78   @LOC("INIT")\r
79   private boolean initialized;\r
80 \r
81   /**\r
82    * Creates a new <code>Decoder</code> instance with default parameters.\r
83    */\r
84 \r
85   public Decoder() {\r
86     this(null);\r
87   }\r
88 \r
89   /**\r
90    * Creates a new <code>Decoder</code> instance with default parameters.\r
91    * \r
92    * @param params\r
93    *          The <code>Params</code> instance that describes the customizable\r
94    *          aspects of the decoder.\r
95    */\r
96   public Decoder(Params params0) {\r
97     if (params0 == null)\r
98       params0 = DEFAULT_PARAMS;\r
99 \r
100     params = params0;\r
101 \r
102     Equalizer eq = params.getInitialEqualizerSettings();\r
103     if (eq != null) {\r
104       equalizer.setFrom(eq);\r
105     }\r
106   }\r
107 \r
108   static public Params getDefaultParams() {\r
109     return (Params) DEFAULT_PARAMS.clone();\r
110   }\r
111 \r
112   public void setEqualizer(Equalizer eq) {\r
113     if (eq == null)\r
114       eq = Equalizer.PASS_THRU_EQ;\r
115 \r
116     equalizer.setFrom(eq);\r
117 \r
118     float[] factors = equalizer.getBandFactors();\r
119 \r
120     if (filter1 != null)\r
121       filter1.setEQ(factors);\r
122 \r
123     if (filter2 != null)\r
124       filter2.setEQ(factors);\r
125   }\r
126 \r
127   /**\r
128    * Decodes one frame from an MPEG audio bitstream.\r
129    * \r
130    * @param header\r
131    *          The header describing the frame to decode.\r
132    * @param bitstream\r
133    *          The bistream that provides the bits for te body of the frame.\r
134    * \r
135    * @return A SampleBuffer containing the decoded samples.\r
136    */\r
137   @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")\r
138   @RETURNLOC("O")\r
139   public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)\r
140       throws DecoderException {\r
141 \r
142     if (!initialized) {\r
143       initialize(header);\r
144     }\r
145 \r
146     @LOC("TH") int layer = header.layer();\r
147 \r
148     output.clear_buffer();\r
149 \r
150     @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return\r
151                                                                                          // ceil=DELTA(TH)\r
152     decoder.decodeFrame();\r
153 \r
154     // if (layer == 3) {\r
155     // if (l3decoder == null) {\r
156     // l3decoder =\r
157     // new LayerIIIDecoder(stream, header, filter1, filter2, output,\r
158     // OutputChannels.BOTH_CHANNELS);\r
159     // }\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
166     // }\r
167     // l2decoder.decodeFrame();\r
168     // } else {\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
173     // }\r
174     // l1decoder.decodeFrame();\r
175     // }\r
176 \r
177     output.write_buffer(1);\r
178 \r
179     return output;\r
180   }\r
181 \r
182   /**\r
183    * Changes the output buffer. This will take effect the next time\r
184    * decodeFrame() is called.\r
185    */\r
186   public void setOutputBuffer(Obuffer out) {\r
187     output = out;\r
188   }\r
189 \r
190   /**\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
193    * stream.\r
194    * \r
195    * @param the\r
196    *          sample rate (in Hz) of the samples written to the output buffer\r
197    *          when decoding.\r
198    */\r
199   public int getOutputFrequency() {\r
200     return outputFrequency;\r
201   }\r
202 \r
203   /**\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
207    * \r
208    * @return The number of output channels in the decoded samples: 1 for mono,\r
209    *         or 2 for stereo.\r
210    * \r
211    */\r
212   public int getOutputChannels() {\r
213     return outputChannels;\r
214   }\r
215 \r
216   /**\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
222    * channels.\r
223    * \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
226    */\r
227   public int getOutputBlockSize() {\r
228     return Obuffer.OBUFFERSIZE;\r
229   }\r
230 \r
231   protected DecoderException newDecoderException(int errorcode) {\r
232     return new DecoderException(errorcode, null);\r
233   }\r
234 \r
235   protected DecoderException newDecoderException(int errorcode, Throwable throwable) {\r
236     return new DecoderException(errorcode, throwable);\r
237   }\r
238 \r
239   @LATTICE("IN,TH,THISLOC=TH")\r
240   @RETURNLOC("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
244 \r
245     // REVIEW: allow channel output selection type\r
246     // (LEFT, RIGHT, BOTH, DOWNMIX)\r
247     switch (layer) {\r
248     case 3:\r
249       if (l3decoder == null) {\r
250         l3decoder =\r
251             new LayerIIIDecoder(header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
252       }\r
253 \r
254       return l3decoder;\r
255       // decoder = l3decoder;\r
256       break;\r
257     case 2:\r
258       if (l2decoder == null) {\r
259         l2decoder = new LayerIIDecoder();\r
260         l2decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
261       }\r
262       return l2decoder;\r
263       // decoder = l2decoder;\r
264       break;\r
265     case 1:\r
266       if (l1decoder == null) {\r
267         l1decoder = new LayerIDecoder();\r
268         l1decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
269       }\r
270       return l1decoder;\r
271       // decoder = l1decoder;\r
272       break;\r
273     }\r
274     //\r
275     // if (decoder==null)\r
276     // {\r
277     // throw newDecoderException(UNSUPPORTED_LAYER, null);\r
278     // }\r
279     //\r
280     // return decoder;\r
281   }\r
282 \r
283   public void initialize(Header header) throws DecoderException {\r
284 \r
285     // REVIEW: allow customizable scale factor\r
286     float scalefactor = 32700.0f;\r
287 \r
288     int mode = header.mode();\r
289     int layer = header.layer();\r
290     int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;\r
291 \r
292     // set up output buffer if not set up by client.\r
293     if (output == null)\r
294       output = new SampleBuffer(header.frequency(), channels);\r
295 \r
296     float[] factors = equalizer.getBandFactors();\r
297     filter1 = new SynthesisFilter(0, scalefactor, factors);\r
298 \r
299     // REVIEW: allow mono output for stereo\r
300     if (channels == 2)\r
301       filter2 = new SynthesisFilter(1, scalefactor, factors);\r
302 \r
303     outputChannels = channels;\r
304     outputFrequency = header.frequency();\r
305 \r
306     initialized = true;\r
307   }\r
308 \r
309   /**\r
310    * The <code>Params</code> class presents the customizable aspects of the\r
311    * decoder.\r
312    * <p>\r
313    * Instances of this class are not thread safe.\r
314    */\r
315   public static class Params implements Cloneable {\r
316     private OutputChannels outputChannels = OutputChannels.BOTH;\r
317 \r
318     private Equalizer equalizer = new Equalizer();\r
319 \r
320     public Params() {\r
321     }\r
322 \r
323     public Object clone() {\r
324       // TODO: need to have better clone method\r
325       Params clone = new Params();\r
326       clone.outputChannels = outputChannels;\r
327       clone.equalizer = equalizer;\r
328       return clone;\r
329       // try\r
330       // {\r
331       // return super.clone();\r
332       // }\r
333       // catch (CloneNotSupportedException ex)\r
334       // {\r
335       // throw new InternalError(this+": "+ex);\r
336       // }\r
337     }\r
338 \r
339     public void setOutputChannels(OutputChannels out) {\r
340       if (out == null)\r
341         throw new NullPointerException("out");\r
342 \r
343       outputChannels = out;\r
344     }\r
345 \r
346     public OutputChannels getOutputChannels() {\r
347       return outputChannels;\r
348     }\r
349 \r
350     /**\r
351      * Retrieves the equalizer settings that the decoder's equalizer will be\r
352      * initialized from.\r
353      * <p>\r
354      * The <code>Equalizer</code> instance returned cannot be changed in real\r
355      * time to affect the decoder output as it is used only to initialize the\r
356      * decoders EQ settings. To affect the decoder's output in realtime, use the\r
357      * Equalizer returned from the getEqualizer() method on the decoder.\r
358      * \r
359      * @return The <code>Equalizer</code> used to initialize the EQ settings of\r
360      *         the decoder.\r
361      */\r
362     public Equalizer getInitialEqualizerSettings() {\r
363       return equalizer;\r
364     }\r
365 \r
366   };\r
367 }\r