Tobias Rundström
2006-08-11 03:02:30 UTC
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-
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
[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-
ret = xmms_xform_read (xform,
(gchar *)data->buffer + data-
err);
if (ret <= 0) {
return ret;
}
data->buffer_length += ret;
mad_stream_buffer (&data->stream, data->buffer, data-
return read;
}
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 attachedat 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;
}