From b926dd100b89baa23cb62d24c56c4a1f793ac55e Mon Sep 17 00:00:00 2001 From: "J. Alexander Treuman" Date: Wed, 26 Jul 2006 03:10:19 +0000 Subject: Use the lame tag's encoder delay/padding to implement gapless mp3 playback git-svn-id: https://svn.musicpd.org/mpd/trunk@4462 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- src/inputPlugins/mp3_plugin.c | 53 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'src/inputPlugins') diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index 549e62af3..86c3742bb 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -52,6 +52,9 @@ #define MUTEFRAME_SKIP 1 #define MUTEFRAME_SEEK 2 +/* the number of samples of silence the decoder inserts at start */ +#define DECODERDELAY 529 + /* this is stolen from mpg321! */ struct audio_dither { mad_fixed_t error[3]; @@ -131,6 +134,12 @@ typedef struct _mp3DecodeData { long highestFrame; long maxFrames; long currentFrame; + int dropFramesAtStart; + int dropFramesAtEnd; + int dropSamplesAtStart; + int dropSamplesAtEnd; + int foundFirstFrame; + int decodedFirstFrame; int flush; unsigned long bitRate; InputStream *inStream; @@ -148,6 +157,12 @@ static void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) data->frameOffset = NULL; data->times = NULL; data->currentFrame = 0; + data->dropFramesAtStart = 0; + data->dropFramesAtEnd = 0; + data->dropSamplesAtStart = 0; + data->dropSamplesAtEnd = 0; + data->foundFirstFrame = 0; + data->decodedFirstFrame = 0; data->flush = 1; data->inStream = inStream; memset(&(data->dither), 0, sizeof(struct audio_dither)); @@ -625,6 +640,11 @@ static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc, found_xing = parse_xing(&xing, &ptr, &bitlen); found_lame = (found_xing ? parse_lame(&lame, &ptr, &bitlen) : 0); + if (found_lame) { + data->dropSamplesAtStart = lame.encoderDelay + DECODERDELAY; + data->dropSamplesAtEnd = lame.encoderPadding; + } + if (found_xing) { if (xing.flags & XING_FRAMES) { mad_timer_t duration = data->frame.header.duration; @@ -707,6 +727,8 @@ static int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data, static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, ReplayGainInfo ** replayGainInfo) { + int samplesPerFrame; + int samplesLeft; int i; int ret; int skip; @@ -749,6 +771,24 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, default: mad_synth_frame(&data->synth, &data->frame); + if (!data->foundFirstFrame) { + samplesPerFrame = (data->synth).pcm.length; + data->dropFramesAtStart = data->dropSamplesAtStart / samplesPerFrame; + data->dropFramesAtEnd = data->dropSamplesAtEnd / samplesPerFrame; + data->dropSamplesAtStart = data->dropSamplesAtStart % samplesPerFrame; + data->dropSamplesAtEnd = data->dropSamplesAtEnd % samplesPerFrame; + data->foundFirstFrame = 1; + } + + if (data->dropFramesAtStart > 0) { + data->dropFramesAtStart--; + break; + } else if ((data->dropFramesAtEnd > 0) && + (data->currentFrame == (data->maxFrames + 1 - data->dropFramesAtEnd))) { + data->dropFramesAtEnd--; + break; + } + if (data->inStream->metaTitle) { MpdTag *tag = newMpdTag(); if (data->inStream->metaName) { @@ -764,9 +804,20 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, freeMpdTag(tag); } + samplesLeft = (data->synth).pcm.length; + for (i = 0; i < (data->synth).pcm.length; i++) { mpd_sint16 *sample; + if (!data->decodedFirstFrame && + (i < data->dropSamplesAtStart)) { + continue; + } else if (data->dropSamplesAtEnd && + (data->currentFrame == (data->maxFrames - data->dropFramesAtEnd))) { + samplesLeft--; + if (samplesLeft < data->dropSamplesAtEnd) break; + } + sample = (mpd_sint16 *) data->outputPtr; *sample = (mpd_sint16) audio_linear_dither(16, (data-> @@ -821,6 +872,8 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, } } + data->decodedFirstFrame = 1; + if (dc->seek && data->inStream->seekable) { long i = 0; data->muteFrame = MUTEFRAME_SEEK; -- cgit v1.2.3