Logo Search packages:      
Sourcecode: libjlayer-java version File versions  Download package

Decoder.java

/*
 * 11/19/04       1.0 moved to LGPL.
 * 01/12/99       Initial version.  mdm@techie.com
 *-----------------------------------------------------------------------
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as published
 *   by the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------
 */
 
package javazoom.jl.decoder;

/**
 * The <code>Decoder</code> class encapsulates the details of
 * decoding an MPEG audio frame. 
 * 
 * @author  MDM   
 * @version 0.0.7 12/12/99
 * @since   0.0.5
 */
00031 public class Decoder implements DecoderErrors
{
      static private final Params DEFAULT_PARAMS = new Params();
      
      /**
       * The Bistream from which the MPEG audio frames are read.
       */
      //private Bitstream                       stream;
      
      /**
       * The Obuffer instance that will receive the decoded
       * PCM samples.
       */
00044       private Obuffer               output;
            
      /**
       * Synthesis filter for the left channel.
       */
00049       private SynthesisFilter             filter1;
      
      /**
       * Sythesis filter for the right channel.
       */
00054       private SynthesisFilter             filter2;    
                  
      /**
       * The decoder used to decode layer III frames.
       */
00059       private LayerIIIDecoder             l3decoder;
      private LayerIIDecoder              l2decoder;
      private LayerIDecoder               l1decoder;
      
      private int                               outputFrequency;
      private int                               outputChannels;
      
      private Equalizer                   equalizer = new Equalizer();
      
      private Params                            params;
      
      private boolean                           initialized;
            
      
      /**
       * Creates a new <code>Decoder</code> instance with default 
       * parameters.
       */
      
00078       public Decoder()
      {
            this(null);
      }

      /**
       * Creates a new <code>Decoder</code> instance with default 
       * parameters.
       * 
       * @param params  The <code>Params</code> instance that describes
       *                            the customizable aspects of the decoder.  
       */
00090       public Decoder(Params params0)
      {
            if (params0==null)
                  params0 = DEFAULT_PARAMS;
      
            params = params0;
            
            Equalizer eq = params.getInitialEqualizerSettings();
            if (eq!=null)
            {
                  equalizer.setFrom(eq);
            }
      }
      
      static public Params getDefaultParams()
      {
            return (Params)DEFAULT_PARAMS.clone();
      }
      
      public void setEqualizer(Equalizer eq)
      {
            if (eq==null)
                  eq = Equalizer.PASS_THRU_EQ;
            
            equalizer.setFrom(eq);
            
            float[] factors = equalizer.getBandFactors();

            if (filter1!=null)
                  filter1.setEQ(factors);
            
            if (filter2!=null)
                  filter2.setEQ(factors);             
      }
      
      /**
       * Decodes one frame from an MPEG audio bitstream.
       * 
       * @param header        The header describing the frame to decode.
       * @param bitstream           The bistream that provides the bits for te body of the frame. 
       * 
       * @return A SampleBuffer containing the decoded samples.
       */
00133       public Obuffer decodeFrame(Header header, Bitstream stream)
            throws DecoderException
      {
            if (!initialized)
            {
                  initialize(header);
            }
            
            int layer = header.layer();
            
            output.clear_buffer();
            
            FrameDecoder decoder = retrieveDecoder(header, stream, layer);
            
            decoder.decodeFrame();
                        
            output.write_buffer(1);
            
            return output;    
      }
      
      /**
       * Changes the output buffer. This will take effect the next time
       * decodeFrame() is called. 
       */
00158       public void setOutputBuffer(Obuffer out)
      {
            output = out;
      }
      
      /**
       * Retrieves the sample frequency of the PCM samples output
       * by this decoder. This typically corresponds to the sample
       * rate encoded in the MPEG audio stream.
       * 
       * @param the sample rate (in Hz) of the samples written to the
       *          output buffer when decoding. 
       */
00171       public int getOutputFrequency()
      {
            return outputFrequency;
      }
      
      /**
       * Retrieves the number of channels of PCM samples output by
       * this decoder. This usually corresponds to the number of
       * channels in the MPEG audio stream, although it may differ.
       * 
       * @return The number of output channels in the decoded samples: 1 
       *          for mono, or 2 for stereo.
       *          
       */
00185       public int getOutputChannels()
      {
            return outputChannels;  
      }
      
      /**
       * Retrieves the maximum number of samples that will be written to
       * the output buffer when one frame is decoded. This can be used to
       * help calculate the size of other buffers whose size is based upon 
       * the number of samples written to the output buffer. NB: this is
       * an upper bound and fewer samples may actually be written, depending
       * upon the sample rate and number of channels.
       * 
       * @return The maximum number of samples that are written to the 
       *          output buffer when decoding a single frame of MPEG audio.
       */
00201       public int getOutputBlockSize()
      {
            return Obuffer.OBUFFERSIZE;
      }
      
      
      protected DecoderException newDecoderException(int errorcode)
      {
            return new DecoderException(errorcode, null);
      }
      
      protected DecoderException newDecoderException(int errorcode, Throwable throwable)
      {
            return new DecoderException(errorcode, throwable);
      }
      
      protected FrameDecoder retrieveDecoder(Header header, Bitstream stream, int layer)
            throws DecoderException
      {
            FrameDecoder decoder = null;
            
            // REVIEW: allow channel output selection type
            // (LEFT, RIGHT, BOTH, DOWNMIX)
            switch (layer)
            {
            case 3:
                  if (l3decoder==null)
                  {
                        l3decoder = new LayerIIIDecoder(stream, 
                              header, filter1, filter2, 
                              output, OutputChannels.BOTH_CHANNELS);
                  }                                   
                  
                  decoder = l3decoder;
                  break;
            case 2:
                  if (l2decoder==null)
                  {
                        l2decoder = new LayerIIDecoder();
                        l2decoder.create(stream, 
                              header, filter1, filter2, 
                              output, OutputChannels.BOTH_CHANNELS);                      
                  }
                  decoder = l2decoder;
                  break;
            case 1:
                  if (l1decoder==null)
                  {
                        l1decoder = new LayerIDecoder();
                        l1decoder.create(stream, 
                              header, filter1, filter2, 
                              output, OutputChannels.BOTH_CHANNELS);                      
                  }
                  decoder = l1decoder;
                  break;
            }
                                    
            if (decoder==null)
            {
                  throw newDecoderException(UNSUPPORTED_LAYER, null);
            }
            
            return decoder;
      }
      
      private void initialize(Header header)
            throws DecoderException
      {
            
            // REVIEW: allow customizable scale factor
            float scalefactor = 32700.0f;
            
            int mode = header.mode();
            int layer = header.layer();
            int channels = mode==Header.SINGLE_CHANNEL ? 1 : 2;

                              
            // set up output buffer if not set up by client.
            if (output==null)
                  output = new SampleBuffer(header.frequency(), channels);
            
            float[] factors = equalizer.getBandFactors();
            filter1 = new SynthesisFilter(0, scalefactor, factors);
            
            // REVIEW: allow mono output for stereo
            if (channels==2) 
                  filter2 = new SynthesisFilter(1, scalefactor, factors);

            outputChannels = channels;
            outputFrequency = header.frequency();
            
            initialized = true;
      }
      
      /**
       * The <code>Params</code> class presents the customizable
       * aspects of the decoder. 
       * <p>
       * Instances of this class are not thread safe. 
       */
00301       public static class Params implements Cloneable
      {
            private OutputChannels  outputChannels = OutputChannels.BOTH;
            
            private Equalizer       equalizer = new Equalizer();
            
            public Params()
            {                 
            }
            
            public Object clone()
            {
                  try
                  {
                        return super.clone();
                  }
                  catch (CloneNotSupportedException ex)
                  {                       
                        throw new InternalError(this+": "+ex);
                  }
            }
                        
            public void setOutputChannels(OutputChannels out)
            {
                  if (out==null)
                        throw new NullPointerException("out");
                  
                  outputChannels = out;
            }
            
            public OutputChannels getOutputChannels()
            {
                  return outputChannels;
            }
            
            /**
             * Retrieves the equalizer settings that the decoder's equalizer
             * will be initialized from.
             * <p>
             * The <code>Equalizer</code> instance returned 
             * cannot be changed in real time to affect the 
             * decoder output as it is used only to initialize the decoders
             * EQ settings. To affect the decoder's output in realtime,
             * use the Equalizer returned from the getEqualizer() method on
             * the decoder. 
             * 
             * @return  The <code>Equalizer</code> used to initialize the
             *                EQ settings of the decoder. 
             */
00350             public Equalizer getInitialEqualizerSettings()
            {
                  return equalizer; 
            }
                        
      };
}


Generated by  Doxygen 1.6.0   Back to index