]> git.sesse.net Git - vlc/blobdiff - modules/codec/mad/libmad.c
* Audio volume management now works properly. See src/audio_output/intf.c
[vlc] / modules / codec / mad / libmad.c
index 4ed0d888d861512dd3ee601c1612a6429a68b0a3..069e29da6aa9de37f0e1a68382e522ab37165749 100644 (file)
@@ -41,452 +41,196 @@ static void PrintFrameInfo(struct mad_header *Header);
  * libmad_input: this function is called by libmad when the input buffer needs
  * to be filled.
  *****************************************************************************/
-enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
+enum mad_flow libmad_input( void *p_data, struct mad_stream *p_stream )
 {
-    mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
-    size_t             ReadSize, Remaining;
-    unsigned char     *ReadStart;
+    mad_adec_thread_t * p_dec = (mad_adec_thread_t *) p_data;
+    size_t   i_wanted, i_left;
 
-    if ( p_mad_adec->p_fifo->b_die == 1 ) {
-        msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" );
+    if ( p_dec->p_fifo->b_die )
+    {
+        msg_Dbg( p_dec->p_fifo, "stopping libmad decoder" );
         return MAD_FLOW_STOP;
     }
 
-    if ( p_mad_adec->p_fifo->b_error == 1 ) {
-        msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" );
+    if ( p_dec->p_fifo->b_error )
+    {
+        msg_Warn( p_dec->p_fifo, "ignoring current audio frame" );
         return MAD_FLOW_IGNORE;
     }
 
-    /* libmad_stream_buffer does not consume the total buffer, it consumes only data
-     * for one frame only. So all data left in the buffer should be put back in front.
-     */
-    if ((p_libmad_stream->buffer==NULL) || (p_libmad_stream->error==MAD_ERROR_BUFLEN))
+    /* libmad_stream_buffer does not consume the total buffer, it consumes
+     * only data for one frame only. So all data left in the buffer should
+     * be put back in front. */
+    if ( !p_stream->buffer || p_stream->error == MAD_ERROR_BUFLEN )
     {
-        /* libmad does not consume all the buffer it's given. Some
-         * datas, part of a truncated frame, is left unused at the
-         * end of the buffer. Those datas must be put back at the
-         * beginning of the buffer and taken in account for
-         * refilling the buffer. This means that the input buffer
-         * must be large enough to hold a complete frame at the
-         * highest observable bit-rate (currently 448 kb/s). XXX=XXX
-         * Is 2016 bytes the size of the largest frame?
-         * (448000*(1152/32000))/8
-         */
-        if(p_libmad_stream->next_frame!=NULL)
+       /* libmad does not consume all the buffer it's given. Some data,
+        * part of a truncated frame, is left unused at the end of the
+        * buffer. Those datas must be put back at the beginning of the
+        * buffer and taken in account for refilling the buffer. This
+        * means that the input buffer must be large enough to hold a
+        * complete frame at the highest observable bit-rate (currently
+        * 448 kb/s). XXX=XXX Is 2016 bytes the size of the largest frame?
+        * (448000*(1152/32000))/8 */
+        if( p_stream->next_frame )
         {
-            Remaining=p_libmad_stream->bufend-p_libmad_stream->next_frame;
-            if( p_mad_adec->buffer != p_libmad_stream->next_frame )
+            i_left = p_stream->bufend - p_stream->next_frame;
+            if( p_dec->buffer != p_stream->next_frame )
             {
-                memcpy( p_mad_adec->buffer,
-                        p_libmad_stream->next_frame, Remaining );
+                memcpy( p_dec->buffer, p_stream->next_frame, i_left );
             }
-            ReadStart=p_mad_adec->buffer+Remaining;
-            ReadSize=(MAD_BUFFER_MDLEN)-Remaining;
+            i_wanted = MAD_BUFFER_MDLEN - i_left;
 
-            /* Store time stamp of next frame */
-            p_mad_adec->i_current_pts = p_mad_adec->i_next_pts;
-            p_mad_adec->i_next_pts = p_mad_adec->p_fifo->p_first->i_pts;
+            /* Store timestamp for next frame */
+            p_dec->i_next_pts = p_dec->p_fifo->p_first->i_pts;
         }
         else
         {
-            ReadSize=(MAD_BUFFER_MDLEN);
-            ReadStart=p_mad_adec->buffer;
-            Remaining=0;
-            p_mad_adec->i_next_pts = 0;
-            p_mad_adec->i_current_pts = p_mad_adec->p_fifo->p_first->i_pts;
+            i_wanted = MAD_BUFFER_MDLEN;
+            i_left = 0;
+
+            /* Store timestamp for this frame */
+            p_dec->i_current_pts = p_dec->p_fifo->p_first->i_pts;
         }
+        p_dec->p_fifo->p_first->i_pts = 0;
 
-        /* Fill-in the buffer. If an error occurs print a message
-         * and leave the decoding loop. If the end of stream is
-         * reached we also leave the loop but the return status is
-         * left untouched.
-         */
-        if( ReadSize > p_mad_adec->p_data->p_payload_end
-                        - p_mad_adec->p_data->p_payload_start )
+        /* Fill-in the buffer. If an error occurs print a message and leave
+         * the decoding loop. If the end of stream is reached we also leave
+         * the loop but the return status is left untouched. */
+        if( i_wanted > p_dec->p_data->p_payload_end
+                        - p_dec->p_data->p_payload_start )
         {
-            ReadSize = p_mad_adec->p_data->p_payload_end
-                        - p_mad_adec->p_data->p_payload_start;
-            memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize );
-            NextDataPacket( p_mad_adec->p_fifo, &p_mad_adec->p_data );
+            i_wanted = p_dec->p_data->p_payload_end
+                        - p_dec->p_data->p_payload_start;
+            memcpy( p_dec->buffer + i_left,
+                    p_dec->p_data->p_payload_start, i_wanted );
+            NextDataPacket( p_dec->p_fifo, &p_dec->p_data );
         }
         else
         {
-            memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize );
-            p_mad_adec->p_data->p_payload_start += ReadSize;
+            memcpy( p_dec->buffer + i_left,
+                    p_dec->p_data->p_payload_start, i_wanted );
+            p_dec->p_data->p_payload_start += i_wanted;
         }
 
-        if ( p_mad_adec->p_fifo->b_die == 1 )
+        if ( p_dec->p_fifo->b_die )
         {
-            msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" );
+            msg_Dbg( p_dec->p_fifo, "stopping libmad decoder" );
             return MAD_FLOW_STOP;
         }
 
-        if ( p_mad_adec->p_fifo->b_error == 1 )
+        if ( p_dec->p_fifo->b_error )
         {
-            msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" );    
+            msg_Warn( p_dec->p_fifo, "ignoring current audio frame" );    
             return MAD_FLOW_IGNORE;
         }
 
         /* Pipe the new buffer content to libmad's stream decoder facility.
-         * Libmad never copies the buffer, but just references it. So keep it in
-         * mad_adec_thread_t structure.
-         */
-        mad_stream_buffer(p_libmad_stream,(unsigned char*) &p_mad_adec->buffer,
-                          Remaining + ReadSize);
-        p_libmad_stream->error=0;
+         * Libmad never copies the buffer, but just references it. So keep
+         * it in mad_adec_thread_t structure. */
+        mad_stream_buffer( p_stream, (unsigned char*) &p_dec->buffer,
+                           i_left + i_wanted );
+        p_stream->error = 0;
     }
 
     return MAD_FLOW_CONTINUE;
 }
 
 /*****************************************************************************
- * libmad_header: this function is called just after the header of a frame is
- * decoded
- *****************************************************************************/
-/*
- *enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header)
- *{
- *   mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
- *
- *   msg_Err( p_mad_adec->p_fifo, "libmad_header samplerate %d", p_libmad_header->samplerate);
- *
- *   PrintFrameInfo(p_limad_mad_header)
- *   return MAD_FLOW_CONTINUE;
- *}
- */
-
-/*****************************************************************************
- * lib_mad_filter: this function is called to filter data of a frame
- *****************************************************************************/
-/* enum mad_flow libmad_filter(void *data, struct mad_stream const *p_libmad_stream, struct mad_frame *p_libmad_frame)
- * {
- *     return MAD_FLOW_CONTINUE;
- * }
- */
-
-///*****************************************************************************
-// * support routines borrowed from mpg321 (file: mad.c), which is distributed
-// * under GPL license
-// *
-// * mpg321 was written by Joe Drew <drew@debian.org>, and based upon 'plaympeg'
-// * from the smpeg sources, which was written by various people from Loki Software
-// * (http://www.lokigames.com).
-// *
-// * It also incorporates some source from mad, written by Robert Leslie
-// *****************************************************************************/
-//
-///* The following two routines and data structure are from the ever-brilliant
-//     Rob Leslie.
-//*/
-//
-//struct audio_dither {
-//    mad_fixed_t error[3];
-//    mad_fixed_t random;
-//};
-//
-///*
-//* NAME:                prng()
-//* DESCRIPTION: 32-bit pseudo-random number generator
-//*/
-//static inline unsigned long prng(unsigned long state)
-//{
-//    return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
-//}
-//
-///*
-//* NAME:        mpg321_s24_to_s16_pcm()
-//* DESCRIPTION: generic linear sample quantize and dither routine
-//*/
-//static inline signed int mpg321_s24_to_s16_pcm(unsigned int bits, mad_fixed_t sample,
-//                                    struct audio_dither *dither)
-//{
-//    unsigned int scalebits;
-//    mad_fixed_t output, mask, random;
-//
-//    enum {
-//        MIN = -MAD_F_ONE,
-//        MAX = MAD_F_ONE - 1
-//    };
-//
-//    /* noise shape */
-//    sample += dither->error[0] - dither->error[1] + dither->error[2];
-//
-//    dither->error[2] = dither->error[1];
-//    dither->error[1] = dither->error[0] / 2;
-//
-//    /* bias */
-//    output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
-//
-//    scalebits = MAD_F_FRACBITS + 1 - bits;
-//    mask = (1L << scalebits) - 1;
-//
-//    /* dither */
-//    random    = prng(dither->random);
-//    output += (random & mask) - (dither->random & mask);
-//
-//    dither->random = random;
-//
-//    /* clip */
-//    if (output > MAX) {
-//        output = MAX;
-//
-//        if (sample > MAX)
-//            sample = MAX;
-//    }
-//    else if (output < MIN) {
-//        output = MIN;
-//
-//        if (sample < MIN)
-//            sample = MIN;
-//    }
-//
-//    /* quantize */
-//    output &= ~mask;
-//
-//    /* error feedback */
-//    dither->error[0] = sample - output;
-//
-//    /* scale */
-//    return output >> scalebits;
-//}
-//
-///*****************************************************************************
-// * s24_to_s16_pcm: Scale a 24 bit pcm sample to a 16 bit pcm sample.
-// *****************************************************************************/
-//static inline mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample)
-//{
-//  /* round */
-//  sample += (1L << (MAD_F_FRACBITS - 16));
-//
-//  /* clip */
-//  if (sample >= MAD_F_ONE)
-//    sample = MAD_F_ONE - 1;
-//  else if (sample < -MAD_F_ONE)
-//    sample = -MAD_F_ONE;
-//
-//  /* quantize */
-//  return sample >> (MAD_F_FRACBITS + 1 - 16);
-//}
-//
-/*****************************************************************************
- * libmad_ouput: this function is called just after the frame is decoded
- *****************************************************************************/
-//enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm)
-//{
-//    mad_adec_thread_t *p_mad_adec= (mad_adec_thread_t *) data;
-//    byte_t *buffer=NULL;
-//    mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1];
-//    register int nsamples = p_libmad_pcm->length;
-//    mad_fixed_t sample;
-//    static struct audio_dither dither;
-//
-//    /* Creating the audio output fifo.
-//     * Assume the samplerate and nr of channels from the first decoded frame is right for the entire audio track.
-//     */
-//    if (p_mad_adec->p_aout_fifo==NULL)
-//    {
-//     p_mad_adec->p_aout_fifo = aout_CreateFifo(
-//                p_mad_adec->p_fifo,
-//                AOUT_FIFO_PCM,              /* fifo type */
-//                2, /*p_libmad_pcm->channels,*/     /* nr. of channels */
-//                p_libmad_pcm->samplerate,   /* frame rate in Hz ?*/
-//                p_libmad_pcm->length*2,     /* length of output buffer *2 channels*/
-//                NULL  );                    /* buffer */
-//
-//     if ( p_mad_adec->p_aout_fifo == NULL )
-//     {
-//             return MAD_FLOW_BREAK;
-//     }
-//
-//        msg_Dbg( p_mad_adec->p_fifo, "aout fifo created");
-//    }
-//
-//    if (p_mad_adec->p_aout_fifo->i_rate != p_libmad_pcm->samplerate)
-//    {
-//     msg_Warn( p_mad_adec->p_fifo, "samplerate is changing from [%d] Hz "
-//                  "to [%d] Hz, sample size [%d], error_code [%0x]",
-//                  p_mad_adec->p_aout_fifo->i_rate, p_libmad_pcm->samplerate,
-//                  p_libmad_pcm->length,
-//                  p_mad_adec->libmad_decoder->sync->stream.error );
-//     p_mad_adec->p_aout_fifo->i_rate = p_libmad_pcm->samplerate;
-//    }
-//
-//    if( p_mad_adec->i_current_pts )
-//    {
-//        p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame]
-//                = p_mad_adec->i_current_pts;
-//    }
-//    else
-//    {
-//        p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame]
-//                = LAST_MDATE;
-//    }
-////    mad_timer_add(&p_mad_adec->libmad_timer,p_libmad_header->duration);
-//
-//    buffer = ((byte_t *)p_mad_adec->p_aout_fifo->buffer) + (p_mad_adec->p_aout_fifo->i_end_frame * (p_libmad_pcm->length*4));
-//
-//    while (nsamples--)
-//    {
-//        switch (p_mad_adec->audio_scaling)
-//        {
-//          case MPG321_SCALING:
-//               sample = mpg321_s24_to_s16_pcm(16, *left_ch++, &dither);
-//          break;
-//          case FAST_SCALING: /* intended fall through */
-//          default:
-//               sample = s24_to_s16_pcm(*left_ch++);
-//          break;
-//                       }
-//
-//        /* left audio channel */
-//#ifndef WORDS_BIGENDIAN
-//        *buffer++ = (byte_t) (sample >> 0);
-//        *buffer++ = (byte_t) (sample >> 8);
-//#else
-//               *buffer++ = (byte_t) (sample >> 8);
-//       *buffer++ = (byte_t) (sample >> 0);
-//#endif
-//             if (p_libmad_pcm->channels == 2)
-//        {
-//                 /* right audio channel */
-//            switch (p_mad_adec->audio_scaling)
-//            {
-//              case MPG321_SCALING:
-//                   sample = mpg321_s24_to_s16_pcm(16, *right_ch++, &dither);
-//              break;
-//              case FAST_SCALING: /* intended fall through */
-//              default:
-//                   sample = s24_to_s16_pcm(*right_ch++);
-//              break;
-//                       }
-//        }
-//        /* else reuse left_ch */
-//#ifndef WORDS_BIGENDIAN
-//        *buffer++ = (byte_t) (sample >> 0);
-//        *buffer++ = (byte_t) (sample >> 8);
-//#else
-//        *buffer++ = (byte_t) (sample >> 8);
-//        *buffer++ = (byte_t) (sample >> 0);
-//#endif                                               
-//    }
-//
-//    /* DEBUG */
-//    /*
-//    if (p_libmad_pcm->channels == 1) {
-//       msg_Dbg( p_mad_adec->p_fifo, "libmad_output channels [%d]", p_libmad_pcm->channels);
-//    }
-//    */
-//
-//    vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
-//    p_mad_adec->p_aout_fifo->i_end_frame = (p_mad_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
-//    vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
-//    vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock);
-//
-//    return MAD_FLOW_CONTINUE;
-//}
-
-/*****************************************************************************
- * libmad_ouput3: this function is called just after the frame is decoded
+ * libmad_output: this function is called just after the frame is decoded
  *****************************************************************************/
-enum mad_flow libmad_output3(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm)
+enum mad_flow libmad_output( void *p_data, struct mad_header const *p_header,
+                             struct mad_pcm *p_pcm )
 {
-    mad_adec_thread_t *p_mad_adec= (mad_adec_thread_t *) data;
-    aout_buffer_t * p_buffer;
-    mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1];
-    register int nsamples = p_libmad_pcm->length;
-    mad_fixed_t sample;
-
-    /* Creating the audio output fifo.
-     * Assume the samplerate and nr of channels from the first decoded frame
-     * is right for the entire audio track.
-     */
-    if( (p_mad_adec->p_aout_input != NULL) &&
-        (p_mad_adec->output_format.i_rate != p_libmad_pcm->samplerate) )
+    mad_adec_thread_t * p_dec = (mad_adec_thread_t *) p_data;
+    aout_buffer_t *     p_buffer;
+    mad_fixed_t const * p_left = p_pcm->samples[0];
+    mad_fixed_t const * p_right = p_pcm->samples[1];
+    int                 i_samples = p_pcm->length;
+    mad_fixed_t *       p_samples;
+
+    /* Creating the audio output fifo. Assume the samplerate and nr of channels
+     * from the first decoded frame is right for the entire audio track. */
+    if( (p_dec->p_aout_input != NULL) &&
+        (p_dec->output_format.i_rate != p_pcm->samplerate
+           || p_dec->output_format.i_channels != p_pcm->channels) )
     {
         /* Parameters changed - this should not happen. */
-        aout_InputDelete( p_mad_adec->p_aout, p_mad_adec->p_aout_input );
-        p_mad_adec->p_aout_input = NULL;
+        aout_InputDelete( p_dec->p_aout, p_dec->p_aout_input );
+        p_dec->p_aout_input = NULL;
     }
 
     /* Creating the audio input if not created yet. */
-    if( p_mad_adec->p_aout_input == NULL )
+    if( p_dec->p_aout_input == NULL )
     {
-        p_mad_adec->output_format.i_rate = p_libmad_pcm->samplerate;
-        /* p_mad_adec->output_format.i_channels = p_libmad_pcm->channels; */
-        p_mad_adec->p_aout_input = aout_InputNew( p_mad_adec->p_fifo,
-                                               &p_mad_adec->p_aout,
-                                               &p_mad_adec->output_format );
+        p_dec->output_format.i_rate = p_pcm->samplerate;
+        p_dec->output_format.i_channels = p_pcm->channels;
+        aout_DateInit( &p_dec->end_date, p_pcm->samplerate );
+        p_dec->p_aout_input = aout_InputNew( p_dec->p_fifo,
+                                             &p_dec->p_aout,
+                                             &p_dec->output_format );
+
+        if ( p_dec->p_aout_input == NULL )
+        {
+            p_dec->p_fifo->b_error = VLC_TRUE;
+            return MAD_FLOW_BREAK;
+        }
+    }
 
-        if ( p_mad_adec->p_aout_input == NULL )
+    if( p_dec->i_current_pts )
+    {
+        /* Set the Presentation Time Stamp */
+        if( p_dec->i_current_pts != aout_DateGet( &p_dec->end_date ) )
         {
-           p_mad_adec->p_fifo->b_error = 1;
-           return MAD_FLOW_BREAK;
+            aout_DateSet( &p_dec->end_date, p_dec->i_current_pts );
         }
-        msg_Dbg( p_mad_adec->p_fifo, "aout3 input created");
+
+        p_dec->i_current_pts = 0;
+    }
+    else if( p_dec->i_next_pts )
+    {
+        /* No PTS this time, but it'll be for next frame */
+        p_dec->i_current_pts = p_dec->i_next_pts;
+        p_dec->i_next_pts = 0;
     }
 
-    if (p_mad_adec->output_format.i_rate != p_libmad_pcm->samplerate)
+    if( !aout_DateGet( &p_dec->end_date ) )
     {
-        msg_Warn( p_mad_adec->p_fifo, "samplerate is changing from [%d] Hz "
-                  "to [%d] Hz, sample size [%d], error_code [%0x]",
-                  p_mad_adec->output_format.i_rate, p_libmad_pcm->samplerate,
-                  p_libmad_pcm->length,
-                  p_mad_adec->libmad_decoder->sync->stream.error );
-        p_mad_adec->output_format.i_rate = p_libmad_pcm->samplerate;
+        /* No date available yet, wait for the first PTS. */
+        return MAD_FLOW_CONTINUE;
     }
 
-    /* Set the Presentation Time Stamp */
-    p_buffer = aout_BufferNew( p_mad_adec->p_aout,
-                               p_mad_adec->p_aout_input,
-                               (p_libmad_pcm->length*2) );
+    p_buffer = aout_BufferNew( p_dec->p_aout, p_dec->p_aout_input, i_samples );
 
     if ( p_buffer == NULL )
     {
-        msg_Dbg( p_mad_adec->p_fifo, "allocating new buffer failed");
+        msg_Err( p_dec->p_fifo, "allocating new buffer failed" );
         return MAD_FLOW_BREAK;
     }
-    /* Add accurate PTS to buffer. */
-    if ( p_mad_adec->i_current_pts )
-    {
-        p_buffer->start_date = p_mad_adec->i_current_pts;
-    }
-    else
-    {
-        p_buffer->start_date = LAST_MDATE;
-    }
-    p_mad_adec->last_date += (mtime_t)(p_libmad_pcm->length*2)
-                             / p_mad_adec->output_format.i_rate;
-    p_buffer->end_date = p_mad_adec->last_date;
+
+    p_buffer->start_date = aout_DateGet( &p_dec->end_date );
+    p_buffer->end_date = aout_DateIncrement( &p_dec->end_date, i_samples );
 
     /* Interleave and keep buffers in mad_fixed_t format */
-    while (nsamples--)
+    p_samples = (mad_fixed_t *)p_buffer->p_buffer;
+
+    switch( p_pcm->channels )
     {
-        /* left audio channel */
-        sample = *left_ch++;
-#ifndef WORDS_BIGENDIAN
-        *(p_buffer->p_buffer)++ = (byte_t) (sample);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-#else
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-#endif
-        /* right audio channel */
-        if (p_libmad_pcm->channels == 2)
+    case 2:
+        while( i_samples-- )
         {
-           sample = *right_ch++;
-        } /* else reuse left audio channel */
-#ifndef WORDS_BIGENDIAN
-        *(p_buffer->p_buffer)++ = (byte_t) (sample);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-#else
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-//        *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-#endif
+            *p_samples++ = *p_left++;
+            *p_samples++ = *p_right++;
+        }
+        break;
+    case 1:
+        p_dec->p_fifo->p_vlc->pf_memcpy( p_samples, p_left,
+                                         i_samples * sizeof(mad_fixed_t) );
+    default:
+        msg_Err( p_dec->p_fifo, "cannot interleave %i channels",
+                                p_pcm->channels );
     }
 
-    aout_BufferPlay( p_mad_adec->p_aout, p_mad_adec->p_aout_input, p_buffer );
+    aout_BufferPlay( p_dec->p_aout, p_dec->p_aout_input, p_buffer );
 
     return MAD_FLOW_CONTINUE;
 }
@@ -494,95 +238,97 @@ enum mad_flow libmad_output3(void *data, struct mad_header const *p_libmad_heade
 /*****************************************************************************
  * libmad_error: this function is called when an error occurs during decoding
  *****************************************************************************/
-enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struct mad_frame *p_libmad_frame)
+enum mad_flow libmad_error( void *data, struct mad_stream *p_libmad_stream,
+                            struct mad_frame *p_libmad_frame )
 {
+    mad_adec_thread_t *p_dec = (mad_adec_thread_t *) data;
     enum mad_flow result = MAD_FLOW_CONTINUE;
 
     switch (p_libmad_stream->error)
     {             
     case MAD_ERROR_BUFLEN:                /* input buffer too small (or EOF) */
-//X        msg_Err("libmad error: input buffer too small (or EOF)");
+        msg_Err( p_dec->p_fifo, "input buffer too small (or EOF)" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BUFPTR:                /* invalid (null) buffer pointer */
-//X        msg_Err("libmad error: invalid (null) buffer pointer");
+        msg_Err( p_dec->p_fifo, "invalid (null) buffer pointer" );
         result = MAD_FLOW_STOP;
         break;
     case MAD_ERROR_NOMEM:                 /* not enough memory */
-//X        msg_Err("libmad error: invalid (null) buffer pointer");
+        msg_Err( p_dec->p_fifo, "invalid (null) buffer pointer" );
         result = MAD_FLOW_STOP;
         break;
     case MAD_ERROR_LOSTSYNC:            /* lost synchronization */
-//X        msg_Err("libmad error: lost synchronization");
+        msg_Err( p_dec->p_fifo, "lost synchronization" );
         mad_stream_sync(p_libmad_stream);
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADLAYER:            /* reserved header layer value */
-//X        msg_Err("libmad error: reserved header layer value");
+        msg_Err( p_dec->p_fifo, "reserved header layer value" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADBITRATE:        /* forbidden bitrate value */
-//X        msg_Err("libmad error: forbidden bitrate value");
+        msg_Err( p_dec->p_fifo, "forbidden bitrate value" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADSAMPLERATE: /* reserved sample frequency value */
-//X        msg_Err("libmad error: reserved sample frequency value");
+        msg_Err( p_dec->p_fifo, "reserved sample frequency value" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADEMPHASIS:     /* reserved emphasis value */
-//X        msg_Err("libmad error: reserverd emphasis value");
+        msg_Err( p_dec->p_fifo, "reserverd emphasis value" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADCRC:                /* CRC check failed */
-//X        msg_Err("libmad error: CRC check failed");
+        msg_Err( p_dec->p_fifo, "CRC check failed" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADBITALLOC:     /* forbidden bit allocation value */
-//X        msg_Err("libmad error: forbidden bit allocation value");
+        msg_Err( p_dec->p_fifo, "forbidden bit allocation value" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADSCALEFACTOR:/* bad scalefactor index */
-//X        msg_Err("libmad error: bad scalefactor index");
+        msg_Err( p_dec->p_fifo, "bad scalefactor index" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADFRAMELEN:     /* bad frame length */
-//X        msg_Err("libmad error: bad frame length");
+        msg_Err( p_dec->p_fifo, "bad frame length" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADBIGVALUES:    /* bad big_values count */
-//X        msg_Err("libmad error: bad big values count");
+        msg_Err( p_dec->p_fifo, "bad big values count" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADBLOCKTYPE:    /* reserved block_type */
-//X        msg_Err("libmad error: reserverd block_type");
+        msg_Err( p_dec->p_fifo, "reserverd block_type" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADSCFSI:            /* bad scalefactor selection info */
-//X        msg_Err("libmad error: bad scalefactor selection info");
+        msg_Err( p_dec->p_fifo, "bad scalefactor selection info" );
         result = MAD_FLOW_CONTINUE;
         break;
     case MAD_ERROR_BADDATAPTR:        /* bad main_data_begin pointer */
-//X        msg_Err("libmad error: bad main_data_begin pointer");
+        msg_Err( p_dec->p_fifo, "bad main_data_begin pointer" );
         result = MAD_FLOW_STOP;
         break;
     case MAD_ERROR_BADPART3LEN:     /* bad audio data length */
-//X        msg_Err("libmad error: bad audio data length");
+        msg_Err( p_dec->p_fifo, "bad audio data length" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADHUFFTABLE:    /* bad Huffman table select */
-//X        msg_Err("libmad error: bad Huffman table select");
+        msg_Err( p_dec->p_fifo, "bad Huffman table select" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADHUFFDATA:     /* Huffman data overrun */
-//X        msg_Err("libmad error: Huffman data overrun");
+        msg_Err( p_dec->p_fifo, "Huffman data overrun" );
         result = MAD_FLOW_IGNORE;
         break;
     case MAD_ERROR_BADSTEREO:         /* incompatible block_type for JS */
-//X        msg_Err("libmad error: incompatible block_type for JS");
+        msg_Err( p_dec->p_fifo, "incompatible block_type for JS" );
         result = MAD_FLOW_IGNORE;
         break;
     default:
-//X        msg_Err("libmad error: unknown error occured stopping decoder");
+        msg_Err( p_dec->p_fifo, "unknown error occured stopping decoder" );
         result = MAD_FLOW_STOP;
         break;
     }
@@ -611,7 +357,7 @@ static void PrintFrameInfo(struct mad_header *Header)
                        *Mode,
                        *Emphasis;
 
-       /* Convert the layer number to it's printed representation. */
+       /* Convert the layer number to its printed representation. */
        switch(Header->layer)
        {
                case MAD_LAYER_I:
@@ -628,7 +374,7 @@ static void PrintFrameInfo(struct mad_header *Header)
                        break;
        }
 
-       /* Convert the audio mode to it's printed representation. */
+       /* Convert the audio mode to its printed representation. */
        switch(Header->mode)
        {
                case MAD_MODE_SINGLE_CHANNEL:
@@ -648,7 +394,7 @@ static void PrintFrameInfo(struct mad_header *Header)
                        break;
        }
 
-       /* Convert the emphasis to it's printed representation. */
+       /* Convert the emphasis to its printed representation. */
        switch(Header->emphasis)
        {
                case MAD_EMPHASIS_NONE: