Discussion:
[mad-user] Gapless decoding with LAME tag reading
Tobias Rundström
2006-08-11 03:02:30 UTC
Permalink
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;
}

Loading...