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