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