e871eec9868fa970297a3df02d00ba32d1dbb332
[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(stream, header, filter1, filter2, output,\r
252                 OutputChannels.BOTH_CHANNELS);\r
253       }\r
254 \r
255       return l3decoder;\r
256       // decoder = l3decoder;\r
257       break;\r
258     case 2:\r
259       if (l2decoder == null) {\r
260         l2decoder = new LayerIIDecoder();\r
261         l2decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
262       }\r
263       return l2decoder;\r
264       // decoder = l2decoder;\r
265       break;\r
266     case 1:\r
267       if (l1decoder == null) {\r
268         l1decoder = new LayerIDecoder();\r
269         l1decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
270       }\r
271       return l1decoder;\r
272       // decoder = l1decoder;\r
273       break;\r
274     }\r
275     //\r
276     // if (decoder==null)\r
277     // {\r
278     // throw newDecoderException(UNSUPPORTED_LAYER, null);\r
279     // }\r
280     //\r
281     // return decoder;\r
282   }\r
283 \r
284   public void initialize(Header header) throws DecoderException {\r
285 \r
286     // REVIEW: allow customizable scale factor\r
287     float scalefactor = 32700.0f;\r
288 \r
289     int mode = header.mode();\r
290     int layer = header.layer();\r
291     int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;\r
292 \r
293     // set up output buffer if not set up by client.\r
294     if (output == null)\r
295       output = new SampleBuffer(header.frequency(), channels);\r
296 \r
297     float[] factors = equalizer.getBandFactors();\r
298     filter1 = new SynthesisFilter(0, scalefactor, factors);\r
299 \r
300     // REVIEW: allow mono output for stereo\r
301     if (channels == 2)\r
302       filter2 = new SynthesisFilter(1, scalefactor, factors);\r
303 \r
304     outputChannels = channels;\r
305     outputFrequency = header.frequency();\r
306 \r
307     initialized = true;\r
308   }\r
309 \r
310   /**\r
311    * The <code>Params</code> class presents the customizable aspects of the\r
312    * 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     private OutputChannels outputChannels = OutputChannels.BOTH;\r
318 \r
319     private Equalizer equalizer = new Equalizer();\r
320 \r
321     public Params() {\r
322     }\r
323 \r
324     public Object clone() {\r
325       // TODO: need to have better clone method\r
326       Params clone = new Params();\r
327       clone.outputChannels = outputChannels;\r
328       clone.equalizer = equalizer;\r
329       return clone;\r
330       // try\r
331       // {\r
332       // return super.clone();\r
333       // }\r
334       // catch (CloneNotSupportedException ex)\r
335       // {\r
336       // throw new InternalError(this+": "+ex);\r
337       // }\r
338     }\r
339 \r
340     public void setOutputChannels(OutputChannels out) {\r
341       if (out == null)\r
342         throw new NullPointerException("out");\r
343 \r
344       outputChannels = out;\r
345     }\r
346 \r
347     public OutputChannels getOutputChannels() {\r
348       return outputChannels;\r
349     }\r
350 \r
351     /**\r
352      * Retrieves the equalizer settings that the decoder's equalizer will be\r
353      * initialized from.\r
354      * <p>\r
355      * The <code>Equalizer</code> instance returned cannot be changed in real\r
356      * time to affect the decoder output as it is used only to initialize the\r
357      * decoders EQ settings. To affect the decoder's output in realtime, use the\r
358      * Equalizer returned from the getEqualizer() method on the decoder.\r
359      * \r
360      * @return The <code>Equalizer</code> used to initialize the EQ settings of\r
361      *         the decoder.\r
362      */\r
363     public Equalizer getInitialEqualizerSettings() {\r
364       return equalizer;\r
365     }\r
366 \r
367   };\r
368 }\r