From e02659f6c0a7ad77fb8e765b0c555342cf3b1752 Mon Sep 17 00:00:00 2001
From: Warren Dukes <warren.dukes@gmail.com>
Date: Tue, 1 Feb 2005 03:20:16 +0000
Subject: will compile if you manually add "HAVE_MUSEPACK" to config.h and
 -lmusepack to MPD_LIBS in Makefile

git-svn-id: https://svn.musicpd.org/mpd/trunk@2919 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 src/Makefile.am               |   1 +
 src/inputPlugin.c             |   2 +
 src/inputPlugins/mpc_plugin.c | 176 ++++++++++++++++++++++++------------------
 3 files changed, 102 insertions(+), 77 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index dbde9a3a0..595259c26 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,7 @@ mpd_inputPlugins = \
 	inputPlugins/mod_plugin.c \
 	inputPlugins/mp3_plugin.c \
 	inputPlugins/mp4_plugin.c \
+	inputPlugins/mpc_plugin.c \
 	inputPlugins/ogg_plugin.c
 
 
diff --git a/src/inputPlugin.c b/src/inputPlugin.c
index 83ba2e38f..2fe20f5fc 100644
--- a/src/inputPlugin.c
+++ b/src/inputPlugin.c
@@ -113,6 +113,7 @@ extern InputPlugin oggPlugin;
 extern InputPlugin flacPlugin;
 extern InputPlugin audiofilePlugin;
 extern InputPlugin mp4Plugin;
+extern InputPlugin mpcPlugin;
 extern InputPlugin aacPlugin;
 extern InputPlugin modPlugin;
 
@@ -125,6 +126,7 @@ void initInputPlugins() {
 	loadInputPlugin(&flacPlugin);
 	loadInputPlugin(&audiofilePlugin);
 	loadInputPlugin(&mp4Plugin);
+	loadInputPlugin(&mpcPlugin);
 	loadInputPlugin(&modPlugin);
 }
 
diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c
index f2c84b22c..4cb53ec06 100644
--- a/src/inputPlugins/mpc_plugin.c
+++ b/src/inputPlugins/mpc_plugin.c
@@ -18,7 +18,7 @@
 
 #include "../inputPlugin.h"
 
-#ifdef HAVE_MPC
+#ifdef HAVE_MUSEPACK
 
 #include "../utils.h"
 #include "../audio.h"
@@ -41,14 +41,14 @@ typedef struct _MpcCallbackData {
 
 /* this is just for tag parsing for db import! */
 int getMpcTotalTime(char * file) {
-	int totalTime = 0
+	int totalTime = 0;
 	
 	return totalTime;
 }
 
-mpc_int32_t mpc_read_cb(void * vdata, void * ptr, size_t size) {
+mpc_int32_t mpc_read_cb(void * vdata, void * ptr, mpc_int32_t size) {
 	mpc_int32_t ret = 0;
-        OggCallbackData * data = (OggCallbackData *)vdata;
+        MpcCallbackData * data = (MpcCallbackData *)vdata;
 
         while(1) {
 	        ret = readFromInputStream(data->inStream, ptr, size, 1);
@@ -63,32 +63,59 @@ mpc_int32_t mpc_read_cb(void * vdata, void * ptr, size_t size) {
 	return ret;
 }
 
-static mpc_bool_t ogg_seek_cb(void * vdata, ogg_int64_t offset) {
-        OggCallbackData * data = (OggCallbackData *)vdata;
+static mpc_bool_t mpc_seek_cb(void * vdata, mpc_int32_t offset) {
+        MpcCallbackData * data = (MpcCallbackData *)vdata;
 
-	return data->inStream->seekable ? 
-		!seekInputStream(data->inStream , offset, SEEK_SET) :
-		false;
+	return !seekInputStream(data->inStream , offset, SEEK_SET);
 }
 
-mpd_int32_t mpc_tell_cb(void * vdata) {
-        OggCallbackData * data = (OggCallbackData *)vdata;
+mpc_int32_t mpc_tell_cb(void * vdata) {
+        MpcCallbackData * data = (MpcCallbackData *)vdata;
 
 	return (long)(data->inStream->offset);
 }
 
 mpc_bool_t mpc_canseek_cb(void * vdata) {
-        OggCallbackData * data = (OggCallbackData *)vdata;
+        MpcCallbackData * data = (MpcCallbackData *)vdata;
 
 	return data->inStream->seekable;
 }
 
 mpc_int32_t mpc_getsize_cb(void * vdata) {
-        OggCallbackData * data = (OggCallbackData *)vdata;
+        MpcCallbackData * data = (MpcCallbackData *)vdata;
 
 	return data->inStream->size;
 }
 
+inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample) {
+	/* only doing 16-bit audio for now */
+	mpd_sint32 val;
+
+        const int clip_min = -1 << (16 - 1);
+        const int clip_max = (1 << (16 - 1)) - 1;
+	
+#ifdef MPC_FIXED_POINT
+	const int shift = 16 - MPC_FIXED_POINT_SCALE_SHIFT;
+
+	if( ssample > 0 ) {
+		sample <<= shift;
+	}
+	else if ( shift < 0 ) {
+		sample >>= -shift;
+	}
+	val = sample;
+#else
+	const int float_scale = 1 << (16 - 1);
+
+	val = sample * float_scale;
+#endif
+
+	if( val < clip_min) val = clip_min;
+	else if ( val > clip_max ) val = clip_max;
+
+	return val;
+}
+
 int mpc_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
 {
 	mpc_decoder decoder;
@@ -96,8 +123,8 @@ int mpc_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
 	mpc_streaminfo info;
 
 	MpcCallbackData data;
-	data.inStream = inStream;
-	data.dc = dc;
+
+	MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
 
 	int eof = 0;
 	long ret;
@@ -105,7 +132,12 @@ int mpc_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
 	char chunk[MPC_CHUNK_SIZE];
 	int chunkpos = 0;
 	long bitRate = 0;
-	char ** comments;
+	mpd_sint16 * s16 = (mpd_sint16 *) chunk;
+	unsigned long samplePos = 0;
+	mpc_uint32_t vbrUpdateAcc;
+	mpc_uint32_t vbrUpdateBits;
+	float time;
+	int i;
 
         data.inStream = inStream;
         data.dc = dc;
@@ -143,75 +175,72 @@ int mpc_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
                 }
 	}
 	
-	dc->totalTime = 0;
+	dc->totalTime = mpc_streaminfo_get_length(&info);
 
 	dc->audioFormat.bits = 16;
+	dc->audioFormat.sampleRate = info.sample_freq;
 
 	while(!eof) {
 		if(dc->seek) {
-			if(0 == ov_time_seek_page(&vf,dc->seekWhere)) {
+			samplePos = dc->seekWhere * dc->audioFormat.sampleRate;
+			if(0 == mpc_decoder_seek_sample(&decoder, samplePos)) {
                                 clearOutputBuffer(cb);
 			        chunkpos = 0;
                         }
                         else dc->seekError = 1;
 			dc->seek = 0;
 		}
-		ret = ov_read(&vf, chunk+chunkpos, 
-				OGG_CHUNK_SIZE-chunkpos,
-				OGG_DECODE_USE_BIGENDIAN,
-				2, 1, &current_section);
-
-		if(current_section!=prev_section) {
-			/*printf("new song!\n");*/
-			vorbis_info *vi=ov_info(&vf,-1);
-			dc->audioFormat.channels = vi->channels;
-			dc->audioFormat.sampleRate = vi->rate;
-			if(dc->state == DECODE_STATE_START) {
-        			getOutputAudioFormat(&(dc->audioFormat),
-					&(cb->audioFormat));
-				dc->state = DECODE_STATE_DECODE;
-			}
-			comments = ov_comment(&vf, -1)->user_comments;
-			putOggCommentsIntoOutputBuffer(cb, inStream->metaName,
-					comments);
-        		ogg_getReplayGainInfo(comments, &replayGainInfo);
-		}
+		ret = mpc_decoder_decode(&decoder, sample_buffer, 
+				         &vbrUpdateAcc, &vbrUpdateBits);
 
-		prev_section = current_section;
-
-		if(ret <= 0 && ret != OV_HOLE) {
+		if(ret <= 0 ) {
 			eof = 1;
 			break;
 		}
-                if(ret == OV_HOLE) ret = 0;
 
-		chunkpos+=ret;
+		samplePos += ret;
 
-		if(chunkpos >= OGG_CHUNK_SIZE) {
-			if((test = ov_bitrate_instant(&vf))>0) {
-				bitRate = test/1000;
-			}
-			sendDataToOutputBuffer(cb, inStream, dc, 
+		/* ret is in samples, and we have stereo */
+		ret *= 2;
+
+		for(i = 0; i < ret; i++) {
+			/* 16 bit audio again */
+			*s16 = convertSample(sample_buffer[i]);
+			chunkpos += 2;
+			s16++;
+
+		       	if(chunkpos >= MPC_CHUNK_SIZE) {
+                                time = ((float)samplePos) /
+				       dc->audioFormat.sampleRate;
+
+				bitRate = vbrUpdateBits * 
+					  dc->audioFormat.sampleRate / 
+					  (MPC_CHUNK_SIZE);
+				
+				sendDataToOutputBuffer(cb, inStream, dc, 
 						inStream->seekable,  
                                         	chunk, chunkpos, 
-						ov_pcm_tell(&vf)/
-						dc->audioFormat.sampleRate,
+						time,
 						bitRate,
-						replayGainInfo);
-			chunkpos = 0;
-			if(dc->stop) break;
+						NULL);
+				chunkpos = 0;
+				s16 = (mpd_sint16 *)chunk;
+				if(dc->stop) break;
+			}
 		}
 	}
 
 	if(!dc->stop && chunkpos > 0) {
+                time = ((float)samplePos) / dc->audioFormat.sampleRate;
+
+		bitRate = vbrUpdateBits * dc->audioFormat.sampleRate /
+			  chunkpos;
+
 		sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
-				chunk, chunkpos,
-				ov_time_tell(&vf), bitRate, replayGainInfo);
+				       chunk, chunkpos, time, bitRate, NULL);
 	}
 
-	if(replayGainInfo) freeReplayGainInfo(replayGainInfo);
-
-	ov_clear(&vf);
+	closeInputStream(inStream);
 
 	flushOutputBuffer(cb);
 
@@ -224,47 +253,40 @@ int mpc_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
 	return 0;
 }
 
-MpdTag * oggTagDup(char * file) {
+MpdTag * mpcTagDup(char * file) {
 	MpdTag * ret = NULL;
 	FILE * fp;
-	OggVorbis_File vf;
 
 	fp = fopen(file,"r"); 
 	if(!fp) return NULL;
-	if(ov_open(fp,&vf,NULL,0)<0) {
-		fclose(fp);
-		return NULL;
-	}
 
-	ret = oggCommentsParse(ov_comment(&vf,-1)->user_comments);
+	/* get tag info here */
 
 	if(!ret) ret = newMpdTag();
-	ret->time = (int)(ov_time_total(&vf,-1)+0.5);
-
-	ov_clear(&vf);
+	ret->time = getMpcTotalTime(file);
 
 	return ret;	
 }
 
-char * oggSuffixes[] = {"ogg", NULL};
-char * oggMimeTypes[] = {"application/ogg", NULL};
+char * mpcSuffixes[] = {"mpc", NULL};
+char * mpcMimeTypes[] = {NULL};
 
-InputPlugin oggPlugin =
+InputPlugin mpcPlugin =
 {
-        "ogg",
+        "mpc",
 	NULL,
 	NULL,
-        ogg_decode,
+        mpc_decode,
         NULL,
-        oggTagDup,
+        mpcTagDup,
         INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
-        oggSuffixes,
-        oggMimeTypes
+        mpcSuffixes,
+        mpcMimeTypes
 };
 
 #else
 
-InputPlugin oggPlugin = 
+InputPlugin mpcPlugin = 
 {
 	NULL,
 	NULL,
-- 
cgit v1.2.3