[mad-user] Gapless decoding with LAME tag reading

Tobias Rundström tru at xmms.org
Thu Aug 10 20:02:30 PDT 2006


Hello List,

I am trying to get our mad decoder in XMMS2 to playback LAME encoded  
files gapless by reading the decoder delay in the header, but I have  
some problems to get it working 100%. The test cases I have is  
confirmed playing gapless in foobar2000 so I guess I just doing  
something wrong :-)

I parse the LAME tag with more or less the same code as in madplay.c  
and then I do:

data->samples_to_skip = lame->start_delay;
data->samples_to_skip_end = lame->end_padding;
data->samples_to_play = (guint64)(((guint64)xmms_xing_get_frames  
(data->xing) * (guint64)1152) - (guint64)lame->start_delay);
XMMS_DBG ("Samples to skip in the beginning: %d, total: %lld", data- 
 >samples_to_skip, data->samples_to_play);

These flags are then used in my decoding function which is attached  
at the bottom.

Still I get around 1000 samples of silence in the beginning when I  
watch the output wave in a wave editor. My theories are that:

1) maybe MAD is adding silence to the output, I read something like  
hinted towards this on the interwebb somewhere.
2) that my find first sync code is not working properly. I feed the  
first frame (that I find the Xing/LAME tag in) back to the decoding  
routine found below, can that produce silence also?
3) My math is off somewhere :-)

Any help on getting this play "perfect" gapless would be very  
appreciated! The full code is available here: http://git.xmms.se/? 
p=xmms2-devel.git;a=tree;;f=src/plugins/mad

-- Tobias

static gint
xmms_mad_read (xmms_xform_t *xform, gpointer buf, gint len,  
xmms_error_t *err)
{
     xmms_mad_data_t *data;
     xmms_samples16_t *out = (xmms_samples16_t *)buf;
     gint ret;
     gint j;
     gint read = 0;

     data = xmms_xform_private_data_get (xform);

     j = 0;

     while (read < len) {

         /* use already synthetized frame first */
         if (data->synthpos < data->synth.pcm.length) {
             if (data->samples_to_skip <= 0 && data->samples_to_play  
 >= 0) {
                 out[j++] = scale_linear (data->synth.pcm.samples[0] 
[data->synthpos]);
                 if (data->channels == 2) {
                     out[j++] = scale_linear (data->synth.pcm.samples 
[1][data->synthpos]);
                     read += 2 * xmms_sample_size_get  
(XMMS_SAMPLE_FORMAT_S16);
                     data->samples_to_play -= 2;
                 } else {
                     read += xmms_sample_size_get  
(XMMS_SAMPLE_FORMAT_S16);
                     data->samples_to_play --;
                 }
             } else {
                 if (data->channels == 2) {
                     data->samples_to_skip -= 2;
                 } else {
                     data->samples_to_skip --;
                 }
             }
             data->synthpos++;
             continue;
         }

         /* then try to decode another frame */
         if (mad_frame_decode (&data->frame, &data->stream) != -1) {
             mad_synth_frame (&data->synth, &data->frame);
             data->synthpos = 0;
             continue;
         }
         /* if there is no frame to decode stream more data */
         if (data->stream.next_frame) {
             guchar *buffer = data->buffer;
             const guchar *nf = data->stream.next_frame;
             memmove (data->buffer, data->stream.next_frame,
                      data->buffer_length = (&buffer[data- 
 >buffer_length] - nf));
         }

         ret = xmms_xform_read (xform,
                                (gchar *)data->buffer + data- 
 >buffer_length,
                                4096 - data->buffer_length,
                                err);

         if (ret <= 0) {
             return ret;
         }

         data->buffer_length += ret;
         mad_stream_buffer (&data->stream, data->buffer, data- 
 >buffer_length);
     }

     return read;
}


More information about the mad-user mailing list