From b926dd100b89baa23cb62d24c56c4a1f793ac55e Mon Sep 17 00:00:00 2001
From: "J. Alexander Treuman" <jat@spatialrift.net>
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