6b8a588c92c258c1077fe8775bd7e7f2d246801f
[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,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("DELTA(TH)") int layer = header.layer();\r
145 \r
146           output.clear_buffer();\r
147 \r
148           @LOC("TH,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer);\r
149           decoder.decodeFrame();\r
150 \r
151           if(layer==3){\r
152             l3decoder=(LayerIIIDecoder)decoder;\r
153           }else if(layer==2){\r
154             l2decoder=(LayerIIDecoder)decoder;\r
155           }else{\r
156             l1decoder=(LayerIDecoder)decoder;\r
157           }\r
158           \r
159           output.write_buffer(1);\r
160 \r
161           return output;        \r
162         }\r
163         \r
164         /**\r
165          * Changes the output buffer. This will take effect the next time\r
166          * decodeFrame() is called. \r
167          */\r
168         public void setOutputBuffer(Obuffer out)\r
169         {\r
170                 output = out;\r
171         }\r
172         \r
173         /**\r
174          * Retrieves the sample frequency of the PCM samples output\r
175          * by this decoder. This typically corresponds to the sample\r
176          * rate encoded in the MPEG audio stream.\r
177          * \r
178          * @param the sample rate (in Hz) of the samples written to the\r
179          *              output buffer when decoding. \r
180          */\r
181         public int getOutputFrequency()\r
182         {\r
183                 return outputFrequency;\r
184         }\r
185         \r
186         /**\r
187          * Retrieves the number of channels of PCM samples output by\r
188          * this decoder. This usually corresponds to the number of\r
189          * channels in the MPEG audio stream, although it may differ.\r
190          * \r
191          * @return The number of output channels in the decoded samples: 1 \r
192          *              for mono, or 2 for stereo.\r
193          *              \r
194          */\r
195         public int getOutputChannels()\r
196         {\r
197                 return outputChannels;  \r
198         }\r
199         \r
200         /**\r
201          * Retrieves the maximum number of samples that will be written to\r
202          * the output buffer when one frame is decoded. This can be used to\r
203          * help calculate the size of other buffers whose size is based upon \r
204          * the number of samples written to the output buffer. NB: this is\r
205          * an upper bound and fewer samples may actually be written, depending\r
206          * upon the sample rate and number of channels.\r
207          * \r
208          * @return The maximum number of samples that are written to the \r
209          *              output buffer when decoding a single frame of MPEG audio.\r
210          */\r
211         public int getOutputBlockSize()\r
212         {\r
213                 return Obuffer.OBUFFERSIZE;\r
214         }\r
215         \r
216         \r
217         protected DecoderException newDecoderException(int errorcode)\r
218         {\r
219                 return new DecoderException(errorcode, null);\r
220         }\r
221         \r
222         protected DecoderException newDecoderException(int errorcode, Throwable throwable)\r
223         {\r
224                 return new DecoderException(errorcode, throwable);\r
225         }\r
226         \r
227         @LATTICE("DE<IN,THISLOC=IN")\r
228         @RETURNLOC("DE")\r
229         protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream, @LOC("IN") int layer)\r
230                 throws DecoderException\r
231         {\r
232                 @LOC("DE") FrameDecoder decoder = null;\r
233                 \r
234                 // REVIEW: allow channel output selection type\r
235                 // (LEFT, RIGHT, BOTH, DOWNMIX)\r
236                 switch (layer)\r
237                 {\r
238                 case 3:\r
239                         if (l3decoder==null)\r
240                         {\r
241                                 l3decoder = new LayerIIIDecoder(stream, \r
242                                         header, filter1, filter2, \r
243                                         output, OutputChannels.BOTH_CHANNELS);\r
244                         }                                               \r
245                         \r
246                         decoder = l3decoder;\r
247                         break;\r
248                 case 2:\r
249                         if (l2decoder==null)\r
250                         {\r
251                                 l2decoder = new LayerIIDecoder();\r
252                                 l2decoder.create(stream, \r
253                                         header, filter1, filter2, \r
254                                         output, OutputChannels.BOTH_CHANNELS);                          \r
255                         }\r
256                         decoder = l2decoder;\r
257                         break;\r
258                 case 1:\r
259                         if (l1decoder==null)\r
260                         {\r
261                                 l1decoder = new LayerIDecoder();\r
262                                 l1decoder.create(stream, \r
263                                         header, filter1, filter2, \r
264                                         output, OutputChannels.BOTH_CHANNELS);                          \r
265                         }\r
266                         decoder = l1decoder;\r
267                         break;\r
268                 }\r
269                                                 \r
270                 if (decoder==null)\r
271                 {\r
272                         throw newDecoderException(UNSUPPORTED_LAYER, null);\r
273                 }\r
274                 \r
275                 return decoder;\r
276         }\r
277         \r
278         public void initialize(Header header, Bitstream stream)\r
279                 throws DecoderException\r
280         {\r
281                 \r
282                 // REVIEW: allow customizable scale factor\r
283                 float scalefactor = 32700.0f;\r
284                 \r
285                 int mode = header.mode();\r
286                 int layer = header.layer();\r
287                 int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;\r
288 \r
289                                         \r
290                 // set up output buffer if not set up by client.\r
291                 if (output==null)\r
292                         output = new SampleBuffer(header.frequency(), channels);\r
293                 \r
294                 float[] factors = equalizer.getBandFactors();\r
295                 filter1 = new SynthesisFilter(0, scalefactor, factors);\r
296                 \r
297                 // REVIEW: allow mono output for stereo\r
298                 if (channels==2) \r
299                         filter2 = new SynthesisFilter(1, scalefactor, factors);\r
300 \r
301                 outputChannels = channels;\r
302                 outputFrequency = header.frequency();\r
303 \r
304                 l3decoder = new LayerIIIDecoder(stream, header, filter1, filter2, \r
305                                                 output, OutputChannels.BOTH_CHANNELS);\r
306                 l2decoder = new LayerIIDecoder();\r
307                 l2decoder.create(stream, header, filter1, filter2, \r
308                                  output, OutputChannels.BOTH_CHANNELS);\r
309 \r
310                 l1decoder = new LayerIDecoder();\r
311                 l1decoder.create(stream,header, filter1, filter2, \r
312                                  output, OutputChannels.BOTH_CHANNELS); \r
313 \r
314                 initialized = true;\r
315         }\r
316         \r
317         /**\r
318          * The <code>Params</code> class presents the customizable\r
319          * aspects of the decoder. \r
320          * <p>\r
321          * Instances of this class are not thread safe. \r
322          */\r
323         public static class Params implements Cloneable\r
324         {\r
325                 private OutputChannels  outputChannels = OutputChannels.BOTH;\r
326                 \r
327                 private Equalizer               equalizer = new Equalizer();\r
328                 \r
329                 public Params()\r
330                 {                       \r
331                 }\r
332                 \r
333                 public Object clone()\r
334                 {\r
335                   //TODO: need to have better clone method\r
336                     Params clone=new Params();\r
337                     clone.outputChannels=outputChannels;\r
338                     clone.equalizer=equalizer;\r
339                     return clone;\r
340 //                      try\r
341 //                      {\r
342 //                              return super.clone();\r
343 //                      }\r
344 //                      catch (CloneNotSupportedException ex)\r
345 //                      {                               \r
346 //                              throw new InternalError(this+": "+ex);\r
347 //                      }\r
348                 }\r
349                                 \r
350                 public void setOutputChannels(OutputChannels out)\r
351                 {\r
352                         if (out==null)\r
353                                 throw new NullPointerException("out");\r
354                         \r
355                         outputChannels = out;\r
356                 }\r
357                 \r
358                 public OutputChannels getOutputChannels()\r
359                 {\r
360                         return outputChannels;\r
361                 }\r
362                 \r
363                 /**\r
364                  * Retrieves the equalizer settings that the decoder's equalizer\r
365                  * will be initialized from.\r
366                  * <p>\r
367                  * The <code>Equalizer</code> instance returned \r
368                  * cannot be changed in real time to affect the \r
369                  * decoder output as it is used only to initialize the decoders\r
370                  * EQ settings. To affect the decoder's output in realtime,\r
371                  * use the Equalizer returned from the getEqualizer() method on\r
372                  * the decoder. \r
373                  * \r
374                  * @return      The <code>Equalizer</code> used to initialize the\r
375                  *                      EQ settings of the decoder. \r
376                  */\r
377                 public Equalizer getInitialEqualizerSettings()\r
378                 {\r
379                         return equalizer;       \r
380                 }\r
381                                 \r
382         };\r
383 }\r
384 \r