Hello,
Here is a patch that add support for libmpcdec in herrie, allowing it to play
musepack files.
Tell me if I need to change anything.
Cheers,
Mawww.
---
herrie/README | 2 +
herrie/configure | 12 ++
herrie/src/audio_file.c | 3 +
herrie/src/audio_format.h | 19 ++++
herrie/src/audio_format_musepack.c | 202 ++++++++++++++++++++++++++++++++++++
5 files changed, 238 insertions(+), 0 deletions(-)
create mode 100644 herrie/src/audio_format_musepack.c
diff --git a/herrie/README b/herrie/README
index 2fd0a31..df455fd 100644
--- a/herrie/README
+++ b/herrie/README
@@ -64,6 +64,7 @@ Herrie:
- libsndfile (optional)
- libspiff (XSPF support, requires 1.0.0 or higher, optional)
- libvorbisfile (optional)
+- libmpcdec (optional)
- ncursesw, ncurses or pdcurses (`XCurses')
- pulseaudio (optional)
@@ -85,6 +86,7 @@ configure script to change certain parameters:
- no_scrobbler Disable AudioScrobbler support
- no_sndfile Disable libsndfile linkage (Wave/FLAC support)
- no_vorbis Disable Ogg Vorbis support
+- no_musepack Disable Musepack support
- no_xspf Disable XSPF (`Spiff') playlist support
- alsa Use ALSA audio output
diff --git a/herrie/configure b/herrie/configure
index f5c172c..5c0db0b 100755
--- a/herrie/configure
+++ b/herrie/configure
@@ -48,6 +48,7 @@ CFG_STRIP=-s
unset CFG_VOLUME
CFG_VORBIS=yes
CFG_XSPF=yes
+CFG_MUSEPACK=yes
DOIT=@
# Operating system defaults
@@ -140,6 +141,9 @@ do
no_vorbis)
unset CFG_VORBIS
;;
+ no_musepack)
+ unset CFG_MUSEPACK
+ ;;
no_xspf)
unset CFG_XSPF
;;
@@ -297,6 +301,13 @@ then
LDFLAGS="$LDFLAGS -lvorbisfile"
SRCS="$SRCS audio_format_vorbis"
fi
+# Musepack support
+if [ "$CFG_MUSEPACK" != "" ]
+then
+ CFLAGS="$CFLAGS -DBUILD_MUSEPACK"
+ LDFLAGS="$LDFLAGS -lmpcdec"
+ SRCS="$SRCS audio_format_musepack"
+fi
# XSPF support
if [ "$CFG_XSPF" != "" ]
then
@@ -374,6 +385,7 @@ echo "- Using $CFG_AO audio output"
[ "$CFG_SCROBBLER" != "" ] && echo "- Support for AudioScrobbler"
[ "$CFG_SNDFILE" != "" ] && echo "- Support for libsndfile"
[ "$CFG_VORBIS" != "" ] && echo "- Support for Ogg Vorbis"
+[ "$CFG_MUSEPACK" != "" ] && echo "- Support for Musepack"
[ "$CFG_XSPF" != "" ] && echo "- Support for XSPF (\`Spiff')"
echo
diff --git a/herrie/src/audio_file.c b/herrie/src/audio_file.c
index 5fb6ec9..9329e74 100644
--- a/herrie/src/audio_file.c
+++ b/herrie/src/audio_file.c
@@ -67,6 +67,9 @@ struct audio_format {
* @brief List of audio formats.
*/
static struct audio_format formats[] = {
+#ifdef BUILD_MUSEPACK
+ { musepack_open, musepack_close, musepack_read, musepack_seek },
+#endif /* !BUILD_MUSEPACK */
#ifdef BUILD_VORBIS
{ vorbis_open, vorbis_close, vorbis_read, vorbis_seek },
#endif /* !BUILD_VORBIS */
diff --git a/herrie/src/audio_format.h b/herrie/src/audio_format.h
index ec75eb1..49f1bf5 100644
--- a/herrie/src/audio_format.h
+++ b/herrie/src/audio_format.h
@@ -105,3 +105,22 @@ size_t vorbis_read(struct audio_file *fd, int16_t *buf,
size_t len);
*/
void vorbis_seek(struct audio_file *fd, int len, int rel);
#endif /* BUILD_VORBIS */
+
+#ifdef BUILD_MUSEPACK
+/**
+ * @brief Open a Musepack file.
+ */
+int musepack_open(struct audio_file *fd, const char *ext);
+/**
+ * @brief Close and clean up the Musepack file.
+ */
+void musepack_close(struct audio_file* fd);
+/**
+ * @brief Read data from the Musepack file and place it in buf.
+ */
+size_t musepack_read(struct audio_file* fd, int16_t *buf, size_t len);
+/**
+ * @brief Seek a relative amount in seconds in the current file handle.
+ */
+void musepack_seek(struct audio_file* fd, int len, int rel);
+#endif /* BUILD_MUSEPACK */
diff --git a/herrie/src/audio_format_musepack.c
b/herrie/src/audio_format_musepack.c
new file mode 100644
index 0000000..e3726fd
--- /dev/null
+++ b/herrie/src/audio_format_musepack.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2008 Maxime COSTE <[EMAIL PROTECTED]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/**
+ * @file audio_format_musepack.c
+ * @brief musepack decompression routines.
+ */
+
+#include "stdinc.h"
+
+#include <mpcdec/mpcdec.h>
+
+#include "audio_file.h"
+#include "audio_format.h"
+#include "audio_output.h"
+
+#define MPC_BUFFER_SIZE 8912*2
+
+/**
+ * @brief Private Musepack data stored in the audio file structure.
+ */
+struct musepack_drv_data {
+ mpc_decoder decoder;
+ mpc_reader reader;
+ mpc_streaminfo info;
+ mpc_int32_t size;
+
+ MPC_SAMPLE_FORMAT buffer[MPC_BUFFER_SIZE];
+ int buf_end;
+ int buf_pos;
+};
+
+/*
+ * Musepack reader implementation
+ */
+mpc_int32_t
+mpc_read_impl(void *data, void *ptr, mpc_int32_t size)
+{
+ struct audio_file *f = (struct audio_file *) data;
+ return fread(ptr, 1, size, f->fp);
+}
+
+mpc_bool_t
+mpc_seek_impl(void *data, mpc_int32_t offset)
+{
+ struct audio_file *f = (struct audio_file *) data;
+ return f->stream ? 0 : !fseek(f->fp, offset, SEEK_SET);
+}
+
+mpc_int32_t
+mpc_tell_impl(void *data)
+{
+ struct audio_file *f = (struct audio_file *) data;
+ return ftell(f->fp);
+}
+
+mpc_int32_t
+mpc_get_size_impl(void *data)
+{
+ struct musepack_drv_data *d = (struct musepack_drv_data *)
+ ((struct audio_file *)data)->drv_data;
+ return d->size;
+}
+
+mpc_bool_t
+mpc_canseek_impl(void *data)
+{
+ struct audio_file *f = (struct audio_file *) data;
+ return !f->stream;
+}
+
+/*
+ * Public API
+ */
+
+int
+musepack_open(struct audio_file *fd, const char *ext)
+{
+ struct musepack_drv_data *data;
+
+ data = g_slice_new(struct musepack_drv_data);
+ fd->drv_data = (void *)data;
+ data->buf_pos = 0;
+ data->buf_end = 0;
+
+ /* setup the mpc reader functions */
+ data->reader.read = mpc_read_impl;
+ data->reader.seek = mpc_seek_impl;
+ data->reader.tell = mpc_tell_impl;
+ data->reader.get_size = mpc_get_size_impl;
+ data->reader.canseek = mpc_canseek_impl;
+ data->reader.data = fd;
+
+ if (!fd->stream) {
+ fseek(fd->fp, 0, SEEK_END);
+ data->size = ftell(fd->fp);
+ fseek(fd->fp, 0, SEEK_SET);
+ } else
+ data->size = 0;
+
+ mpc_streaminfo_init(&data->info);
+ if (mpc_streaminfo_read(&data->info, &data->reader) != ERROR_CODE_OK) {
+ /* not a musepack file */
+ g_slice_free(struct musepack_drv_data, data);
+ return -1;
+ }
+
+ fd->srate = data->info.sample_freq;
+ fd->channels = data->info.channels;
+ fd->time_len = mpc_streaminfo_get_length(&data->info);
+
+ /* initialize the mpc decoder */
+ mpc_decoder_setup(&data->decoder, &data->reader);
+ if (!mpc_decoder_initialize(&data->decoder, &data->info)) {
+ g_slice_free(struct musepack_drv_data, data);
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+musepack_close(struct audio_file* fd)
+{
+ struct musepack_drv_data *data = (struct musepack_drv_data *)fd->drv_data;
+ g_slice_free(struct musepack_drv_data, data);
+}
+
+#ifdef MPC_FIXED_POINT
+#define TO_INT16(x) x >> 16
+#else
+/*
+ * looks like sometimes libmpcdec returns floats slightly over 1.0f, so I do
+ * not use 0x7FFF as a scale to avoid some audio artifacts
+ */
+#define TO_INT16(x) x * (0x6FFF)
+#endif
+
+size_t
+musepack_read(struct audio_file* fd, int16_t *buf, size_t len)
+{
+ struct musepack_drv_data *data = (struct musepack_drv_data *)fd->drv_data;
+ int copied = 0;
+ size_t rlen;
+
+ /* copy already decoded data in the buffer */
+ while (data->buf_pos < data->buf_end)
+ buf[copied++] = TO_INT16(data->buffer[data->buf_pos++]);
+
+ data->buf_pos = 0;
+ data->buf_end = 0;
+
+ /* decode some new data */
+ while (data->buf_end < len - copied) {
+ rlen = mpc_decoder_decode(&data->decoder,
+ &data->buffer[data->buf_end],
+ 0, 0);
+ if (rlen <= 0)
+ break;
+ data->buf_end += rlen * fd->channels;
+ }
+
+ /* convert samples to 16 bit */
+ while (copied < len && data->buf_pos < data->buf_end)
+ buf[copied++] = TO_INT16(data->buffer[data->buf_pos++]);
+
+ return copied;
+}
+
+void
+musepack_seek(struct audio_file* fd, int len, int rel)
+{
+ struct musepack_drv_data *data = (struct musepack_drv_data *)fd->drv_data;
+ int pos = len;
+ /* not supported yet */
+ if (rel)
+ pos += 0;
+ mpc_decoder_seek_seconds(&data->decoder, pos);
+}
+
--
1.5.6.4