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