* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
*----------------------------------------------------------------------\r
*/\r
- \r
\r
/**\r
- * The <code>Decoder</code> class encapsulates the details of\r
- * decoding an MPEG audio frame. \r
+ * The <code>Decoder</code> class encapsulates the details of decoding an MPEG\r
+ * audio frame.\r
* \r
- * @author MDM \r
+ * @author MDM\r
* @version 0.0.7 12/12/99\r
- * @since 0.0.5\r
+ * @since 0.0.5\r
*/\r
@LATTICE("ST,DE<OUT,DE<FIL,DE<LA,O,EQ,PA,INIT,DE*")\r
-public class Decoder implements DecoderErrors\r
-{\r
- static private final Params DEFAULT_PARAMS = new Params();\r
- \r
- /**\r
- * The Bistream from which the MPEG audio frames are read.\r
- */\r
- @LOC("ST") private Bitstream stream;\r
- \r
- /**\r
- * The Obuffer instance that will receive the decoded\r
- * PCM samples.\r
- */\r
- @LOC("OUT") private Obuffer output;\r
- \r
- /**\r
- * Synthesis filter for the left channel.\r
- */\r
- @LOC("FIL") private SynthesisFilter filter1;\r
- \r
- /**\r
- * Sythesis filter for the right channel.\r
- */\r
- @LOC("FIL") private SynthesisFilter filter2; \r
- \r
- /**\r
- * The decoder used to decode layer III frames.\r
- */\r
- @LOC("DE") private LayerIIIDecoder l3decoder;\r
- @LOC("DE") private LayerIIDecoder l2decoder;\r
- @LOC("DE") private LayerIDecoder l1decoder;\r
- \r
- @LOC("O") private int outputFrequency;\r
- @LOC("O") private int outputChannels;\r
- \r
- @LOC("EQ") private Equalizer equalizer = new Equalizer();\r
- \r
- @LOC("PA") private Params params;\r
- \r
- @LOC("INIT") private boolean initialized;\r
- \r
- \r
- /**\r
- * Creates a new <code>Decoder</code> instance with default \r
- * parameters.\r
- */\r
- \r
- public Decoder()\r
- {\r
- this(null);\r
- }\r
-\r
- /**\r
- * Creates a new <code>Decoder</code> instance with default \r
- * parameters.\r
- * \r
- * @param params The <code>Params</code> instance that describes\r
- * the customizable aspects of the decoder. \r
- */\r
- public Decoder(Params params0)\r
- {\r
- if (params0==null)\r
- params0 = DEFAULT_PARAMS;\r
- \r
- params = params0;\r
- \r
- Equalizer eq = params.getInitialEqualizerSettings();\r
- if (eq!=null)\r
- {\r
- equalizer.setFrom(eq);\r
- }\r
- }\r
- \r
- static public Params getDefaultParams()\r
- {\r
- return (Params)DEFAULT_PARAMS.clone();\r
- }\r
- \r
- public void setEqualizer(Equalizer eq)\r
- {\r
- if (eq==null)\r
- eq = Equalizer.PASS_THRU_EQ;\r
- \r
- equalizer.setFrom(eq);\r
- \r
- float[] factors = equalizer.getBandFactors();\r
-\r
- if (filter1!=null)\r
- filter1.setEQ(factors);\r
- \r
- if (filter2!=null)\r
- filter2.setEQ(factors); \r
- }\r
- \r
- /**\r
- * Decodes one frame from an MPEG audio bitstream.\r
- * \r
- * @param header The header describing the frame to decode.\r
- * @param bitstream The bistream that provides the bits for te body of the frame. \r
- * \r
- * @return A SampleBuffer containing the decoded samples.\r
- */\r
- @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")\r
- @RETURNLOC("O")\r
- public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)\r
- throws DecoderException\r
- {\r
- // throw decoder initialization out of ssjava loop since it is invoked once\r
- // if (!initialized)\r
- // {\r
- // initialize(header,stream);\r
- // }\r
-\r
- @LOC("TH") int layer = header.layer();\r
-\r
- output.clear_buffer();\r
-\r
-// @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return ceil=DELTA(TH)\r
-// decoder.decodeFrame();\r
-\r
- if(layer==3){\r
- if (l3decoder==null)\r
- {\r
- l3decoder = new LayerIIIDecoder(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- } \r
- l3decoder.decodeFrame();\r
- }else if(layer==2){\r
- if (l2decoder==null)\r
- {\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- l2decoder.decodeFrame();\r
- }else{\r
- if (l1decoder==null)\r
- {\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- l1decoder.decodeFrame();\r
- }\r
-\r
- output.write_buffer(1);\r
-\r
- return output; \r
- }\r
- \r
- /**\r
- * Changes the output buffer. This will take effect the next time\r
- * decodeFrame() is called. \r
- */\r
- public void setOutputBuffer(Obuffer out)\r
- {\r
- output = out;\r
- }\r
- \r
- /**\r
- * Retrieves the sample frequency of the PCM samples output\r
- * by this decoder. This typically corresponds to the sample\r
- * rate encoded in the MPEG audio stream.\r
- * \r
- * @param the sample rate (in Hz) of the samples written to the\r
- * output buffer when decoding. \r
- */\r
- public int getOutputFrequency()\r
- {\r
- return outputFrequency;\r
- }\r
- \r
- /**\r
- * Retrieves the number of channels of PCM samples output by\r
- * this decoder. This usually corresponds to the number of\r
- * channels in the MPEG audio stream, although it may differ.\r
- * \r
- * @return The number of output channels in the decoded samples: 1 \r
- * for mono, or 2 for stereo.\r
- * \r
- */\r
- public int getOutputChannels()\r
- {\r
- return outputChannels; \r
- }\r
- \r
- /**\r
- * Retrieves the maximum number of samples that will be written to\r
- * the output buffer when one frame is decoded. This can be used to\r
- * help calculate the size of other buffers whose size is based upon \r
- * the number of samples written to the output buffer. NB: this is\r
- * an upper bound and fewer samples may actually be written, depending\r
- * upon the sample rate and number of channels.\r
- * \r
- * @return The maximum number of samples that are written to the \r
- * output buffer when decoding a single frame of MPEG audio.\r
- */\r
- public int getOutputBlockSize()\r
- {\r
- return Obuffer.OBUFFERSIZE;\r
- }\r
- \r
- \r
- protected DecoderException newDecoderException(int errorcode)\r
- {\r
- return new DecoderException(errorcode, null);\r
- }\r
- \r
- protected DecoderException newDecoderException(int errorcode, Throwable throwable)\r
- {\r
- return new DecoderException(errorcode, throwable);\r
- }\r
- \r
- @LATTICE("IN,TH,THISLOC=TH")\r
- @RETURNLOC("TH")\r
- protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream, @LOC("IN") int layer)\r
- throws DecoderException\r
- {\r
-// @LOC("DE") FrameDecoder decoder = null;\r
- \r
- // REVIEW: allow channel output selection type\r
- // (LEFT, RIGHT, BOTH, DOWNMIX)\r
- switch (layer)\r
- {\r
- case 3:\r
- if (l3decoder==null)\r
- {\r
- l3decoder = new LayerIIIDecoder(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- } \r
- \r
- return l3decoder;\r
-// decoder = l3decoder;\r
- break;\r
- case 2:\r
- if (l2decoder==null)\r
- {\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- return l2decoder;\r
-// decoder = l2decoder;\r
- break;\r
- case 1:\r
- if (l1decoder==null)\r
- {\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream, \r
- header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
- }\r
- return l1decoder;\r
-// decoder = l1decoder;\r
- break;\r
- }\r
-// \r
-// if (decoder==null)\r
-// {\r
-// throw newDecoderException(UNSUPPORTED_LAYER, null);\r
-// }\r
-// \r
-// return decoder;\r
- }\r
- \r
- public void initialize(Header header, Bitstream stream)\r
- throws DecoderException\r
- {\r
- \r
- // REVIEW: allow customizable scale factor\r
- float scalefactor = 32700.0f;\r
- \r
- int mode = header.mode();\r
- int layer = header.layer();\r
- int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;\r
-\r
- \r
- // set up output buffer if not set up by client.\r
- if (output==null)\r
- output = new SampleBuffer(header.frequency(), channels);\r
- \r
- float[] factors = equalizer.getBandFactors();\r
- filter1 = new SynthesisFilter(0, scalefactor, factors);\r
- \r
- // REVIEW: allow mono output for stereo\r
- if (channels==2) \r
- filter2 = new SynthesisFilter(1, scalefactor, factors);\r
-\r
- outputChannels = channels;\r
- outputFrequency = header.frequency();\r
-\r
- l3decoder = new LayerIIIDecoder(stream, header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
- l2decoder = new LayerIIDecoder();\r
- l2decoder.create(stream, header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS);\r
-\r
- l1decoder = new LayerIDecoder();\r
- l1decoder.create(stream,header, filter1, filter2, \r
- output, OutputChannels.BOTH_CHANNELS); \r
-\r
- initialized = true;\r
- }\r
- \r
- /**\r
- * The <code>Params</code> class presents the customizable\r
- * aspects of the decoder. \r
- * <p>\r
- * Instances of this class are not thread safe. \r
- */\r
- public static class Params implements Cloneable\r
- {\r
- private OutputChannels outputChannels = OutputChannels.BOTH;\r
- \r
- private Equalizer equalizer = new Equalizer();\r
- \r
- public Params()\r
- { \r
- }\r
- \r
- public Object clone()\r
- {\r
- //TODO: need to have better clone method\r
- Params clone=new Params();\r
- clone.outputChannels=outputChannels;\r
- clone.equalizer=equalizer;\r
- return clone;\r
-// try\r
-// {\r
-// return super.clone();\r
-// }\r
-// catch (CloneNotSupportedException ex)\r
-// { \r
-// throw new InternalError(this+": "+ex);\r
-// }\r
- }\r
- \r
- public void setOutputChannels(OutputChannels out)\r
- {\r
- if (out==null)\r
- throw new NullPointerException("out");\r
- \r
- outputChannels = out;\r
- }\r
- \r
- public OutputChannels getOutputChannels()\r
- {\r
- return outputChannels;\r
- }\r
- \r
- /**\r
- * Retrieves the equalizer settings that the decoder's equalizer\r
- * will be initialized from.\r
- * <p>\r
- * The <code>Equalizer</code> instance returned \r
- * cannot be changed in real time to affect the \r
- * decoder output as it is used only to initialize the decoders\r
- * EQ settings. To affect the decoder's output in realtime,\r
- * use the Equalizer returned from the getEqualizer() method on\r
- * the decoder. \r
- * \r
- * @return The <code>Equalizer</code> used to initialize the\r
- * EQ settings of the decoder. \r
- */\r
- public Equalizer getInitialEqualizerSettings()\r
- {\r
- return equalizer; \r
- }\r
- \r
- };\r
-}\r
+public class Decoder implements DecoderErrors {\r
+ static private final Params DEFAULT_PARAMS = new Params();\r
+\r
+ /**\r
+ * The Bistream from which the MPEG audio frames are read.\r
+ */\r
+ @LOC("ST")\r
+ private Bitstream stream;\r
+\r
+ /**\r
+ * The Obuffer instance that will receive the decoded PCM samples.\r
+ */\r
+ @LOC("OUT")\r
+ private Obuffer output;\r
+\r
+ /**\r
+ * Synthesis filter for the left channel.\r
+ */\r
+ @LOC("FIL")\r
+ private SynthesisFilter filter1;\r
+\r
+ /**\r
+ * Sythesis filter for the right channel.\r
+ */\r
+ @LOC("FIL")\r
+ private SynthesisFilter filter2;\r
+\r
+ /**\r
+ * The decoder used to decode layer III frames.\r
+ */\r
+ @LOC("DE")\r
+ private LayerIIIDecoder l3decoder;\r
+ @LOC("DE")\r
+ private LayerIIDecoder l2decoder;\r
+ @LOC("DE")\r
+ private LayerIDecoder l1decoder;\r
+\r
+ @LOC("O")\r
+ private int outputFrequency;\r
+ @LOC("O")\r
+ private int outputChannels;\r
+\r
+ @LOC("EQ")\r
+ private Equalizer equalizer = new Equalizer();\r
+\r
+ @LOC("PA")\r
+ private Params params;\r
+\r
+ @LOC("INIT")\r
+ private boolean initialized;\r
+\r
+ /**\r
+ * Creates a new <code>Decoder</code> instance with default parameters.\r
+ */\r
+\r
+ public Decoder() {\r
+ this(null);\r
+ }\r
+\r
+ /**\r
+ * Creates a new <code>Decoder</code> instance with default parameters.\r
+ * \r
+ * @param params\r
+ * The <code>Params</code> instance that describes the customizable\r
+ * aspects of the decoder.\r
+ */\r
+ public Decoder(Params params0) {\r
+ if (params0 == null)\r
+ params0 = DEFAULT_PARAMS;\r
+\r
+ params = params0;\r
+\r
+ Equalizer eq = params.getInitialEqualizerSettings();\r
+ if (eq != null) {\r
+ equalizer.setFrom(eq);\r
+ }\r
+ }\r
+\r
+ static public Params getDefaultParams() {\r
+ return (Params) DEFAULT_PARAMS.clone();\r
+ }\r
+\r
+ public void setEqualizer(Equalizer eq) {\r
+ if (eq == null)\r
+ eq = Equalizer.PASS_THRU_EQ;\r
+\r
+ equalizer.setFrom(eq);\r
+\r
+ float[] factors = equalizer.getBandFactors();\r
+\r
+ if (filter1 != null)\r
+ filter1.setEQ(factors);\r
+\r
+ if (filter2 != null)\r
+ filter2.setEQ(factors);\r
+ }\r
+\r
+ /**\r
+ * Decodes one frame from an MPEG audio bitstream.\r
+ * \r
+ * @param header\r
+ * The header describing the frame to decode.\r
+ * @param bitstream\r
+ * The bistream that provides the bits for te body of the frame.\r
+ * \r
+ * @return A SampleBuffer containing the decoded samples.\r
+ */\r
+ @LATTICE("O<DE,DE<TH,TH<IN,THISLOC=TH")\r
+ @RETURNLOC("O")\r
+ public Obuffer decodeFrame(@LOC("IN") Header header, @LOC("IN") Bitstream stream)\r
+ throws DecoderException {\r
+\r
+ if (!initialized) {\r
+ initialize(header);\r
+ }\r
+\r
+ @LOC("TH") int layer = header.layer();\r
+\r
+ output.clear_buffer();\r
+\r
+ @LOC("DE,Decoder.DE") FrameDecoder decoder = retrieveDecoder(header, stream, layer); // return\r
+ // ceil=DELTA(TH)\r
+ decoder.decodeFrame();\r
+\r
+ // if (layer == 3) {\r
+ // if (l3decoder == null) {\r
+ // l3decoder =\r
+ // new LayerIIIDecoder(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l3decoder.decodeFrame();\r
+ // } else if (layer == 2) {\r
+ // if (l2decoder == null) {\r
+ // l2decoder = new LayerIIDecoder();\r
+ // l2decoder.create(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l2decoder.decodeFrame();\r
+ // } else {\r
+ // if (l1decoder == null) {\r
+ // l1decoder = new LayerIDecoder();\r
+ // l1decoder.create(stream, header, filter1, filter2, output,\r
+ // OutputChannels.BOTH_CHANNELS);\r
+ // }\r
+ // l1decoder.decodeFrame();\r
+ // }\r
+\r
+ output.write_buffer(1);\r
\r
+ return output;\r
+ }\r
+\r
+ /**\r
+ * Changes the output buffer. This will take effect the next time\r
+ * decodeFrame() is called.\r
+ */\r
+ public void setOutputBuffer(Obuffer out) {\r
+ output = out;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the sample frequency of the PCM samples output by this decoder.\r
+ * This typically corresponds to the sample rate encoded in the MPEG audio\r
+ * stream.\r
+ * \r
+ * @param the\r
+ * sample rate (in Hz) of the samples written to the output buffer\r
+ * when decoding.\r
+ */\r
+ public int getOutputFrequency() {\r
+ return outputFrequency;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the number of channels of PCM samples output by this decoder.\r
+ * This usually corresponds to the number of channels in the MPEG audio\r
+ * stream, although it may differ.\r
+ * \r
+ * @return The number of output channels in the decoded samples: 1 for mono,\r
+ * or 2 for stereo.\r
+ * \r
+ */\r
+ public int getOutputChannels() {\r
+ return outputChannels;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the maximum number of samples that will be written to the output\r
+ * buffer when one frame is decoded. This can be used to help calculate the\r
+ * size of other buffers whose size is based upon the number of samples\r
+ * written to the output buffer. NB: this is an upper bound and fewer samples\r
+ * may actually be written, depending upon the sample rate and number of\r
+ * channels.\r
+ * \r
+ * @return The maximum number of samples that are written to the output buffer\r
+ * when decoding a single frame of MPEG audio.\r
+ */\r
+ public int getOutputBlockSize() {\r
+ return Obuffer.OBUFFERSIZE;\r
+ }\r
+\r
+ protected DecoderException newDecoderException(int errorcode) {\r
+ return new DecoderException(errorcode, null);\r
+ }\r
+\r
+ protected DecoderException newDecoderException(int errorcode, Throwable throwable) {\r
+ return new DecoderException(errorcode, throwable);\r
+ }\r
+\r
+ @LATTICE("IN,TH,THISLOC=TH")\r
+ @RETURNLOC("TH")\r
+ protected FrameDecoder retrieveDecoder(@LOC("IN") Header header, @LOC("IN") Bitstream stream,\r
+ @LOC("IN") int layer) throws DecoderException {\r
+ // @LOC("DE") FrameDecoder decoder = null;\r
+\r
+ // REVIEW: allow channel output selection type\r
+ // (LEFT, RIGHT, BOTH, DOWNMIX)\r
+ switch (layer) {\r
+ case 3:\r
+ if (l3decoder == null) {\r
+ l3decoder =\r
+ new LayerIIIDecoder(header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
+ }\r
+\r
+ return l3decoder;\r
+ // decoder = l3decoder;\r
+ break;\r
+ case 2:\r
+ if (l2decoder == null) {\r
+ l2decoder = new LayerIIDecoder();\r
+ l2decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
+ }\r
+ return l2decoder;\r
+ // decoder = l2decoder;\r
+ break;\r
+ case 1:\r
+ if (l1decoder == null) {\r
+ l1decoder = new LayerIDecoder();\r
+ l1decoder.create(stream, header, filter1, filter2, output, OutputChannels.BOTH_CHANNELS);\r
+ }\r
+ return l1decoder;\r
+ // decoder = l1decoder;\r
+ break;\r
+ }\r
+ //\r
+ // if (decoder==null)\r
+ // {\r
+ // throw newDecoderException(UNSUPPORTED_LAYER, null);\r
+ // }\r
+ //\r
+ // return decoder;\r
+ }\r
+\r
+ public void initialize(Header header) throws DecoderException {\r
+\r
+ // REVIEW: allow customizable scale factor\r
+ float scalefactor = 32700.0f;\r
+\r
+ int mode = header.mode();\r
+ int layer = header.layer();\r
+ int channels = mode == Header.SINGLE_CHANNEL ? 1 : 2;\r
+\r
+ // set up output buffer if not set up by client.\r
+ if (output == null)\r
+ output = new SampleBuffer(header.frequency(), channels);\r
+\r
+ float[] factors = equalizer.getBandFactors();\r
+ filter1 = new SynthesisFilter(0, scalefactor, factors);\r
+\r
+ // REVIEW: allow mono output for stereo\r
+ if (channels == 2)\r
+ filter2 = new SynthesisFilter(1, scalefactor, factors);\r
+\r
+ outputChannels = channels;\r
+ outputFrequency = header.frequency();\r
+\r
+ initialized = true;\r
+ }\r
+\r
+ /**\r
+ * The <code>Params</code> class presents the customizable aspects of the\r
+ * decoder.\r
+ * <p>\r
+ * Instances of this class are not thread safe.\r
+ */\r
+ public static class Params implements Cloneable {\r
+ private OutputChannels outputChannels = OutputChannels.BOTH;\r
+\r
+ private Equalizer equalizer = new Equalizer();\r
+\r
+ public Params() {\r
+ }\r
+\r
+ public Object clone() {\r
+ // TODO: need to have better clone method\r
+ Params clone = new Params();\r
+ clone.outputChannels = outputChannels;\r
+ clone.equalizer = equalizer;\r
+ return clone;\r
+ // try\r
+ // {\r
+ // return super.clone();\r
+ // }\r
+ // catch (CloneNotSupportedException ex)\r
+ // {\r
+ // throw new InternalError(this+": "+ex);\r
+ // }\r
+ }\r
+\r
+ public void setOutputChannels(OutputChannels out) {\r
+ if (out == null)\r
+ throw new NullPointerException("out");\r
+\r
+ outputChannels = out;\r
+ }\r
+\r
+ public OutputChannels getOutputChannels() {\r
+ return outputChannels;\r
+ }\r
+\r
+ /**\r
+ * Retrieves the equalizer settings that the decoder's equalizer will be\r
+ * initialized from.\r
+ * <p>\r
+ * The <code>Equalizer</code> instance returned cannot be changed in real\r
+ * time to affect the decoder output as it is used only to initialize the\r
+ * decoders EQ settings. To affect the decoder's output in realtime, use the\r
+ * Equalizer returned from the getEqualizer() method on the decoder.\r
+ * \r
+ * @return The <code>Equalizer</code> used to initialize the EQ settings of\r
+ * the decoder.\r
+ */\r
+ public Equalizer getInitialEqualizerSettings() {\r
+ return equalizer;\r
+ }\r
+\r
+ };\r
+}\r