Index: /bmp-musepack/trunk/CMakeLists.txt
===================================================================
--- /bmp-musepack/trunk/CMakeLists.txt	(revision 456)
+++ /bmp-musepack/trunk/CMakeLists.txt	(revision 456)
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 2.4)
+
+project(audacious_musepack CXX)
+
+SET(CMAKE_VERBOSE_MAKEFILE FALSE)
+SET(CMAKE_CXX_FLAGS "-Wall")
+IF(NOT CMAKE_BUILD_TYPE)
+  SET(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING
+      "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+      FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+FIND_PACKAGE(GTK2 REQUIRED gtk)
+
+FIND_PATH(MPCDEC_INCLUDE_DIR mpc/mpc_types.h
+	${audacious_musepack_SOURCE_DIR}/../libmpc/include
+	/usr/local/include
+	/usr/include
+)
+
+FIND_PATH(MOWGLI_INCLUDE_DIR mowgli.h
+	/usr/local/include/libmowgli
+	/usr/include/libmowgli
+)
+
+FIND_PATH(AUD_INPUT_PLUGIN_DIR Input
+	/usr/local/lib/audacious
+	/usr/lib/audacious
+)
+
+FIND_LIBRARY(MPCDEC_LIBRARY NAMES mpcdec PATHS
+	/usr/local/lib
+	/usr/lib
+)
+
+include_directories(${GTK2_INCLUDE_DIRS} ${MPCDEC_INCLUDE_DIR} ${MOWGLI_INCLUDE_DIR})
+link_directories(${GTK_LIBRARIES} ${MPCDEC_LIBRARY})
+
+add_library(musepack MODULE libmpc)
+target_link_libraries(musepack pthread mpcdec glib-2.0 tag gtk-x11-2.0)
+SET_TARGET_PROPERTIES(musepack PROPERTIES PREFIX "")
+
+install(TARGETS musepack LIBRARY DESTINATION "${AUD_INPUT_PLUGIN_DIR}/Input/")
Index: /bmp-musepack/trunk/COPYING
===================================================================
--- /bmp-musepack/trunk/COPYING	(revision 455)
+++ /bmp-musepack/trunk/COPYING	(revision 456)
@@ -1,3 +1,3 @@
-Copyright (c) 2005, The Musepack Development Team
+Copyright (c) 2005-2009, The Musepack Development Team
 All rights reserved.
 
Index: /bmp-musepack/trunk/ChangeLog
===================================================================
--- /bmp-musepack/trunk/ChangeLog	(revision 455)
+++ /bmp-musepack/trunk/ChangeLog	(revision 456)
@@ -1,2 +1,7 @@
+1.3
+	Changes for libmpcdec 1.3.0 (sv8 support)
+	Changes for Audacious 2.1.0
+	Moved to cmake build system
+
 1.2
 	General code refactoring
@@ -7,13 +12,13 @@
 	Safer multithreading
 	Updated for libmpcdec-1.2
-						
+
 1.1.2
 	port to new C libmusepack
-	
+
 1.1
 	Autotools building process
 	%d now display full date tag
 
-1.1-alpha10 
+1.1-alpha10
 	Equalizer works now
 	Fixed a small Bug with skipping broken tracks
@@ -45,4 +50,4 @@
 	fixed tag reading
 
-1.1-alpha: 
+1.1-alpha:
 	rewrite from scratch using musepack lib
Index: /bmp-musepack/trunk/INSTALL
===================================================================
--- /bmp-musepack/trunk/INSTALL	(revision 455)
+++ /bmp-musepack/trunk/INSTALL	(revision 456)
@@ -1,9 +1,12 @@
-Bmp-musepack plugin
+Audacious-musepack plugin
 Required:
 	Taglib headers and libs >= 1.4
 	GTK-2.0 headers and libs
-	Bmp-0.9.7 headers and binaries
-	libmpcdec >= 1.2
+	Audacious-2.1.0 headers and binaries
+	libmpcdec >= 1.3.0
 To install:
-run "./configure && make" as user
-run "make install" as root
+mkdir build
+cd build
+cmake ..
+make
+make install
Index: p-musepack/trunk/Makefile.am
===================================================================
--- /bmp-musepack/trunk/Makefile.am	(revision 455)
+++ 	(revision )
@@ -1,3 +1,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-SUBDIRS = src
Index: p-musepack/trunk/autogen.sh
===================================================================
--- /bmp-musepack/trunk/autogen.sh	(revision 455)
+++ 	(revision )
@@ -1,6 +1,0 @@
-#! /bin/sh
-libtoolize --copy
-aclocal
-autoheader
-automake --gnu --add-missing --copy
-autoconf
Index: p-musepack/trunk/configure.ac
===================================================================
--- /bmp-musepack/trunk/configure.ac	(revision 455)
+++ 	(revision )
@@ -1,105 +1,0 @@
-AC_INIT
-AC_CONFIG_SRCDIR([src/libmpc.cpp])
-AC_CONFIG_AUX_DIR(config)
-AM_INIT_AUTOMAKE(libmpc,1.2)
-AC_CONFIG_HEADER(src/config.h)
-
-VERSION="1.2"
-
-AC_PROG_CXX
-AM_DISABLE_STATIC
-AC_PROG_LIBTOOL
-AC_PROG_INSTALL
-
-CXXFLAGS="-O3 -fomit-frame-pointer"
-
-AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h wchar.h])
-
-AC_HEADER_STDBOOL
-AC_C_CONST
-AC_TYPE_OFF_T
-AC_TYPE_SIZE_T
-
-PKG_CHECK_MODULES(AUDACIOUS, [audclient >= 1.0.0],
-	[],
-	[AC_MSG_ERROR([AUDACIOUS >= 1.0.0 development package not installed])]
-)
-
-AUD_PLUGIN_DIR=`pkg-config --variable input_plugin_dir audacious`
-AC_SUBST(AUD_PLUGIN_DIR)
-
-PKG_CHECK_MODULES(GTK, [gtk+-2.0 >= 2.4.0],
-	[],
-	[AC_MSG_ERROR([GTK+2 >= 2.4.0 development package not installed])]
-)
-
-PKG_CHECK_MODULES(GLIB_2_0, [glib-2.0 >= 2.0.0],
-	[],
-	[AC_MSG_ERROR([GLib+2 >= 2.0.0 development package not installed])]
-)
-
-AC_CHECK_HEADERS(mpc/mpc_types.h,,AC_MSG_ERROR([*** Libmpcdec not installed - please install first ***]))
-
-AC_DEFUN([AC_HAVE_TAGLIB],
-[
-    AC_DEFINE(HAVE_TAGLIB, 1, [Have TagLib])
-    TAGLIB_CFLAGS=[`$TAGLIB_CONFIG --cflags`]
-    TAGLIB_LIBS=[`$TAGLIB_CONFIG --libs`]
-    HAVE_TAGLIB=true
-])
-AC_DEFUN([AC_NO_TAGLIB],
-[
-    AC_MSG_ERROR([*** Taglib not installed - please install first])
-])
-
-AC_PATH_PROG(TAGLIB_CONFIG, taglib-config, [no], [$PATH:$prefix/bin])
-if test "x$TAGLIB_CONFIG" = "xno" ; then
-    AC_NO_TAGLIB
-else
-    AC_HAVE_TAGLIB
-fi
-AC_SUBST(TAGLIB_CFLAGS)
-AC_SUBST(TAGLIB_LIBS)
-
-dnl ---------- END TAGLIB CHECK ----------
-
-dnl pthread libs
-
-AC_CHECK_HEADER(pthread.h,,AC_MSG_ERROR([*** POSIX thread support not installed - please install first ***]))
-
-PTHREAD_LIBS=error
-AC_MSG_CHECKING(for old style FreeBSD -pthread flag)
-AC_EGREP_CPP(yes,
-	[#if (defined(__FreeBSD_cc_version) && __FreeBSD_cc_version <= 500001) || defined(__OpenBSD__)
-	  yes
-	#endif
-	], AC_MSG_RESULT(yes)
-	CFLAGS="$CFLAGS -D_THREAD_SAFE" PTHREAD_LIBS="-pthread",
-	AC_MSG_RESULT(no))
-if test "x$PTHREAD_LIBS" = xerror; then
-	AC_CHECK_LIB(pthread, pthread_attr_init,
-		PTHREAD_LIBS="-lpthread")
-fi
-if test "x$PTHREAD_LIBS" = xerror; then
-	AC_CHECK_LIB(pthreads, pthread_attr_init,
-     		PTHREAD_LIBS="-lpthreads")
-fi
-if test "x$PTHREAD_LIBS" = xerror; then
-	AC_CHECK_LIB(c_r, pthread_attr_init,
-     		PTHREAD_LIBS="-lc_r")
-fi
-if test "x$PTHREAD_LIBS" = xerror; then
-	AC_CHECK_FUNC(pthread_attr_init, PTHREAD_LIBS="")
-fi
-if test "x$PTHREAD_LIBS" = xerror; then
-	AC_MSG_ERROR(*** Unable to locate working posix thread library ***)
-fi
-AC_SUBST(PTHREAD_LIBS)
-
-dnl
-
-AC_SUBST(VERSION)
-AC_CONFIG_FILES([Makefile src/Makefile])
-AC_OUTPUT
-AC_MSG_RESULT([=> Bmp-musepack $VERSION configured successfully.])
Index: /bmp-musepack/trunk/libmpc.cpp
===================================================================
--- /bmp-musepack/trunk/libmpc.cpp	(revision 456)
+++ /bmp-musepack/trunk/libmpc.cpp	(revision 456)
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 2005-2009, The Musepack Development Team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * 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.
+ *
+ *     * Neither the name of the The Musepack Development Team nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+
+#include "libmpc.h"
+
+#define REMOVE_NONEXISTANT_TAG(x)   if (!*x) { x = NULL; }
+#define VERSION "1.3"
+#define PACKAGE "aud_mpc"
+
+using TagLib::MPC::File;
+using TagLib::Tag;
+using TagLib::String;
+using TagLib::APE::ItemListMap;
+
+static PluginConfig pluginConfig = {0};
+static Widgets      widgets      = {0};
+static MpcDecoder   mpcDecoder   = {0};
+static TrackInfo    track        = {0};
+
+static GThread            *threadHandle;
+static GStaticMutex threadMutex = G_STATIC_MUTEX_INIT;
+
+/*
+ * VFS callback implementation, adapted from mpc_reader.c.
+ * This _IS_ very sick, but it works. -nenolod
+ */
+static mpc_int32_t
+aud_vfs_fread_impl(mpc_reader *d, void *ptr, mpc_int32_t size)
+{
+    VFSFile *file = (VFSFile *) d->data;
+
+    return (mpc_int32_t) aud_vfs_fread(ptr, 1, size, file);
+}
+
+static mpc_bool_t
+aud_vfs_fseek_impl(mpc_reader *d, mpc_int32_t offset)
+{
+    VFSFile *file = (VFSFile *) d->data;
+
+	return d->canseek(d) ? aud_vfs_fseek(file, offset, SEEK_SET) == 0 : FALSE;
+}
+
+static mpc_int32_t
+aud_vfs_ftell_impl(mpc_reader *d)
+{
+    VFSFile *file = (VFSFile *) d->data;
+
+    return aud_vfs_ftell(file);
+}
+
+static mpc_int32_t
+aud_vfs_getsize_impl(mpc_reader *d)
+{
+	int f_pos, f_size;
+	VFSFile *file = (VFSFile *) d->data;
+
+	f_pos = aud_vfs_ftell(file);
+	aud_vfs_fseek(file, 0, SEEK_END);
+	f_size = aud_vfs_ftell(file);
+	aud_vfs_fseek(file, f_pos, SEEK_SET);
+
+	return f_size;
+}
+
+static mpc_bool_t
+aud_vfs_canseek_impl(mpc_reader *d)
+{
+    return TRUE; // FIXME : can we really always seek ?
+}
+
+/*
+ * This sets up an mpc_reader object to read from VFS instead of libc.
+ * Essentially, we use this instead of the normal constructor.
+ *    - nenolod
+ */
+void
+mpc_reader_setup_file_vfs(mpc_reader *p_reader, VFSFile *input)
+{
+    p_reader->seek = aud_vfs_fseek_impl;
+    p_reader->read = aud_vfs_fread_impl;
+    p_reader->tell = aud_vfs_ftell_impl;
+    p_reader->get_size = aud_vfs_getsize_impl;
+    p_reader->canseek = aud_vfs_canseek_impl;
+	p_reader->data = input; // no worries, it gets cast back -nenolod
+	aud_vfs_fseek(input, 0, SEEK_SET);
+}
+
+static void mpcOpenPlugin()
+{
+    mcs_handle_t *cfg;
+    cfg = aud_cfg_db_open();
+    aud_cfg_db_get_bool(cfg, "musepack", "clipPrevention", &pluginConfig.clipPrevention);
+    aud_cfg_db_get_bool(cfg, "musepack", "albumGain",      &pluginConfig.albumGain);
+    aud_cfg_db_get_bool(cfg, "musepack", "dynamicBitrate", &pluginConfig.dynamicBitrate);
+    aud_cfg_db_get_bool(cfg, "musepack", "replaygain",     &pluginConfig.replaygain);
+    aud_cfg_db_close(cfg);
+}
+
+static void mpcAboutBox()
+{
+    GtkWidget* aboutBox = widgets.aboutBox;
+    if (aboutBox)
+        gdk_window_raise(aboutBox->window);
+    else
+    {
+        char* titleText      = g_strdup_printf(_("Musepack Decoder Plugin %s"), VERSION);
+        const char* contentText = _("Plugin code by\nBenoit Amiaux\nMartin Spuler\nKuniklo\nNicolas Botti\n\nGet latest version at http://musepack.net\n");
+        const char* buttonText  = _("Nevermind");
+        aboutBox = audacious_info_dialog(titleText, contentText, buttonText, FALSE, NULL, NULL);
+        widgets.aboutBox = aboutBox;
+        g_signal_connect(G_OBJECT(aboutBox), "destroy", G_CALLBACK(gtk_widget_destroyed), &widgets.aboutBox);
+    }
+}
+
+static void toggleSwitch(GtkWidget* p_Widget, gpointer p_Data)
+{
+    gtk_widget_set_sensitive(GTK_WIDGET(p_Data), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p_Widget)));
+}
+
+static void mpcConfigBox()
+{
+    GtkWidget* configBox = widgets.configBox;
+    if(configBox)
+        gdk_window_raise(configBox->window);
+    else
+    {
+        configBox = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+        gtk_window_set_type_hint(GTK_WINDOW(configBox), GDK_WINDOW_TYPE_HINT_DIALOG);
+        widgets.configBox = configBox;
+        g_signal_connect(G_OBJECT(configBox), "destroy", G_CALLBACK(gtk_widget_destroyed), &widgets.configBox);
+        gtk_window_set_title(GTK_WINDOW(configBox), _("Musepack Decoder Configuration"));
+        gtk_window_set_resizable(GTK_WINDOW(configBox), FALSE);
+        gtk_container_set_border_width(GTK_CONTAINER(configBox), 10);
+
+        GtkWidget* notebook = gtk_notebook_new();
+        GtkWidget* vbox = gtk_vbox_new(FALSE, 10);
+        gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+        gtk_container_add(GTK_CONTAINER(configBox), vbox);
+
+        //General Settings Tab
+        GtkWidget* generalSet = gtk_frame_new(_("General Settings"));
+        gtk_container_set_border_width(GTK_CONTAINER(generalSet), 5);
+
+        GtkWidget* gSvbox = gtk_vbox_new(FALSE, 10);
+        gtk_container_set_border_width(GTK_CONTAINER(gSvbox), 5);
+        gtk_container_add(GTK_CONTAINER(generalSet), gSvbox);
+
+        GtkWidget* bitrateCheck = gtk_check_button_new_with_label(_("Enable Dynamic Bitrate Display"));
+        widgets.bitrateCheck = bitrateCheck;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bitrateCheck), pluginConfig.dynamicBitrate);
+        gtk_box_pack_start(GTK_BOX(gSvbox), bitrateCheck, FALSE, FALSE, 0);
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), generalSet, gtk_label_new(_("Plugin")));
+
+        //ReplayGain Settings Tab
+        GtkWidget* replaygainSet = gtk_frame_new(_("ReplayGain Settings"));
+        gtk_container_set_border_width(GTK_CONTAINER(replaygainSet), 5);
+
+        GtkWidget* rSVbox = gtk_vbox_new(FALSE, 10);
+        gtk_container_set_border_width(GTK_CONTAINER(rSVbox), 5);
+        gtk_container_add(GTK_CONTAINER(replaygainSet), rSVbox);
+
+        GtkWidget* clippingCheck = gtk_check_button_new_with_label(_("Enable Clipping Prevention"));
+        widgets.clippingCheck = clippingCheck;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(clippingCheck), pluginConfig.clipPrevention);
+        gtk_box_pack_start(GTK_BOX(rSVbox), clippingCheck, FALSE, FALSE, 0);
+
+        GtkWidget* replaygainCheck = gtk_check_button_new_with_label(_("Enable ReplayGain"));
+        widgets.replaygainCheck = replaygainCheck;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygainCheck), pluginConfig.replaygain);
+        gtk_box_pack_start(GTK_BOX(rSVbox), replaygainCheck, FALSE, FALSE, 0);
+
+        GtkWidget* replaygainType = gtk_frame_new(_("ReplayGain Type"));
+        gtk_box_pack_start(GTK_BOX(rSVbox), replaygainType, FALSE, FALSE, 0);
+        g_signal_connect(G_OBJECT(replaygainCheck), "toggled", G_CALLBACK(toggleSwitch), replaygainType);
+
+        GtkWidget* rgVbox = gtk_vbox_new(FALSE, 5);
+        gtk_container_set_border_width(GTK_CONTAINER(rgVbox), 5);
+        gtk_container_add(GTK_CONTAINER(replaygainType), rgVbox);
+
+        GtkWidget* trackCheck = gtk_radio_button_new_with_label(NULL, _("Use Track Gain"));
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(trackCheck), !pluginConfig.albumGain);
+        gtk_box_pack_start(GTK_BOX(rgVbox), trackCheck, FALSE, FALSE, 0);
+
+        GtkWidget* albumCheck = gtk_radio_button_new_with_label(gtk_radio_button_get_group(GTK_RADIO_BUTTON(trackCheck)), _("Use Album Gain"));
+        widgets.albumCheck = albumCheck;
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(albumCheck), pluginConfig.albumGain);
+        gtk_box_pack_start(GTK_BOX(rgVbox), albumCheck, FALSE, FALSE, 0);
+        gtk_widget_set_sensitive(replaygainType, pluginConfig.replaygain);
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), replaygainSet, gtk_label_new(_("ReplayGain")));
+
+        //Buttons
+        GtkWidget* buttonBox = gtk_hbutton_box_new();
+        gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
+        gtk_box_set_spacing(GTK_BOX(buttonBox), 5);
+        gtk_box_pack_start(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0);
+
+        GtkWidget* okButton = gtk_button_new_with_label(_("Ok"));
+        g_signal_connect(G_OBJECT(okButton), "clicked", G_CALLBACK(saveConfigBox), NULL);
+        GTK_WIDGET_SET_FLAGS(okButton, GTK_CAN_DEFAULT);
+        gtk_box_pack_start(GTK_BOX(buttonBox), okButton, TRUE, TRUE, 0);
+
+        GtkWidget* cancelButton = gtk_button_new_with_label(_("Cancel"));
+        g_signal_connect_swapped(G_OBJECT(cancelButton), "clicked", G_CALLBACK(gtk_widget_destroy), GTK_OBJECT(widgets.configBox));
+        GTK_WIDGET_SET_FLAGS(cancelButton, GTK_CAN_DEFAULT);
+        gtk_widget_grab_default(cancelButton);
+        gtk_box_pack_start(GTK_BOX(buttonBox), cancelButton, TRUE, TRUE, 0);
+
+        gtk_widget_show_all(configBox);
+    }
+}
+
+static void saveConfigBox(GtkWidget* p_Widget, gpointer p_Data)
+{
+    mcs_handle_t* cfg;
+    GtkToggleButton* tb;
+
+    tb = GTK_TOGGLE_BUTTON(widgets.replaygainCheck);
+    pluginConfig.replaygain = gtk_toggle_button_get_active(tb);
+    tb = GTK_TOGGLE_BUTTON(widgets.clippingCheck);
+    pluginConfig.clipPrevention = gtk_toggle_button_get_active(tb);
+    tb = GTK_TOGGLE_BUTTON(widgets.bitrateCheck);
+    pluginConfig.dynamicBitrate = gtk_toggle_button_get_active(tb);
+    tb = GTK_TOGGLE_BUTTON(widgets.albumCheck);
+    pluginConfig.albumGain = gtk_toggle_button_get_active(tb);
+
+    cfg = aud_cfg_db_open();
+
+    aud_cfg_db_set_bool(cfg, "musepack", "clipPrevention", pluginConfig.clipPrevention);
+    aud_cfg_db_set_bool(cfg, "musepack", "albumGain",      pluginConfig.albumGain);
+    aud_cfg_db_set_bool(cfg, "musepack", "dynamicBitrate", pluginConfig.dynamicBitrate);
+    aud_cfg_db_set_bool(cfg, "musepack", "replaygain",     pluginConfig.replaygain);
+
+    aud_cfg_db_close(cfg);
+
+    gtk_widget_destroy (widgets.configBox);
+}
+
+static gint mpcIsOurFD(gchar* p_Filename, VFSFile* file)
+{
+    gchar magic[4];
+    aud_vfs_fread(magic, 1, 4, file);
+    if (memcmp(magic, "MP+", 3) == 0)
+        return 1;
+	if (memcmp(magic, "MPCK", 4) == 0)
+		return 1;
+    return 0;
+}
+
+static void mpcPlay(InputPlayback *data)
+{
+    mpcDecoder.offset   = -1;
+    mpcDecoder.isAlive  = true;
+    mpcDecoder.isOutput = false;
+    mpcDecoder.isPause  = false;
+    threadHandle = g_thread_self();
+    decodeStream(data);
+}
+
+static void mpcStop(InputPlayback *data)
+{
+    mpcDecoder.isAlive = false;
+    if (threadHandle)
+    {
+        g_thread_join(threadHandle);
+        if (mpcDecoder.isOutput)
+        {
+            data->output->buffer_free();
+            data->output->close_audio();
+            mpcDecoder.isOutput = false;
+        }
+    }
+}
+
+inline static void lockAcquire()
+{
+    g_static_mutex_lock(&threadMutex);
+}
+
+inline static void lockRelease()
+{
+    g_static_mutex_unlock(&threadMutex);
+}
+
+static void mpcPause(InputPlayback *data, short p_Pause)
+{
+    lockAcquire();
+    mpcDecoder.isPause = p_Pause;
+    data->output->pause(p_Pause);
+    lockRelease();
+}
+
+static void mpcSeekm(InputPlayback *data, gulong ms_offset)
+{
+    lockAcquire();
+    mpcDecoder.offset = ms_offset;
+    lockRelease();
+}
+
+static void mpcSeek(InputPlayback *data, int p_Offset)
+{
+	mpcSeekm(data, 1000 * p_Offset);
+}
+
+static MpcInfo getTags(const gchar* p_Filename)
+{
+    gchar *pRealFilename = g_filename_from_uri(p_Filename, NULL, NULL);
+    File oFile(pRealFilename ? pRealFilename : p_Filename, false);
+    g_free(pRealFilename);
+    Tag* poTag = oFile.tag();
+    MpcInfo tags = {0};
+    tags.title   = g_strdup(poTag->title().toCString(true));
+    REMOVE_NONEXISTANT_TAG(tags.title);
+    tags.artist  = g_strdup(poTag->artist().toCString(true));
+    REMOVE_NONEXISTANT_TAG(tags.artist);
+    tags.album   = g_strdup(poTag->album().toCString(true));
+    REMOVE_NONEXISTANT_TAG(tags.album);
+    tags.genre   = g_strdup(poTag->genre().toCString(true));
+    REMOVE_NONEXISTANT_TAG(tags.genre);
+    tags.comment = g_strdup(poTag->comment().toCString(true));
+    REMOVE_NONEXISTANT_TAG(tags.comment);
+    tags.year    = poTag->year();
+    tags.track   = poTag->track();
+#if 0
+    TagLib::APE::Tag* ape = oFile.APETag(false);
+    if(ape)
+    {
+        ItemListMap map = ape->itemListMap();
+        if(map.contains("YEAR"))
+        {
+            tags.date = g_strdup(map["YEAR"].toString().toCString(true));
+        }
+        else
+        {
+            tags.date = g_strdup_printf("%d", tags.year);
+        }
+    }
+#endif
+    return tags;
+}
+
+static void removeTags(GtkWidget * w, gpointer data)
+{
+    File oFile(gtk_entry_get_text(GTK_ENTRY(widgets.fileEntry)));
+    oFile.remove();
+    oFile.save();
+    closeInfoBox(NULL, NULL);
+}
+
+static void saveTags(GtkWidget* w, gpointer data)
+{
+    File oFile(gtk_entry_get_text(GTK_ENTRY(widgets.fileEntry)));
+    Tag* poTag = oFile.tag();
+
+    gchar* cAlbum   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.albumEntry)));
+    gchar* cArtist  = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.artistEntry)));
+    gchar* cTitle   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.titleEntry)));
+    gchar* cGenre   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.genreEntry)));
+    gchar* cComment = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.commentEntry)));
+
+    const String album   = String(cAlbum,   TagLib::String::UTF8);
+    const String artist  = String(cArtist,  TagLib::String::UTF8);
+    const String title   = String(cTitle,   TagLib::String::UTF8);
+    const String genre   = String(cGenre,   TagLib::String::UTF8);
+    const String comment = String(cComment, TagLib::String::UTF8);
+
+    poTag->setAlbum(album);
+    poTag->setArtist(artist);
+    poTag->setTitle(title);
+    poTag->setGenre(genre);
+    poTag->setComment(comment);
+    poTag->setYear(atoi(gtk_entry_get_text(GTK_ENTRY(widgets.yearEntry))));
+    poTag->setTrack(atoi(gtk_entry_get_text(GTK_ENTRY(widgets.trackEntry))));
+
+    g_free(cAlbum);
+    g_free(cArtist);
+    g_free(cTitle);
+    g_free(cGenre);
+    g_free(cComment);
+
+    oFile.save();
+    closeInfoBox(NULL, NULL);
+}
+
+static void freeTags(MpcInfo& tags)
+{
+    g_free(tags.title);
+    g_free(tags.artist);
+    g_free(tags.album);
+    g_free(tags.comment);
+    g_free(tags.genre);
+    g_free(tags.date);
+}
+
+static Tuple *mpcGetTuple(gchar* p_Filename, VFSFile *input)
+{
+	Tuple *tuple = 0;
+	bool close_input = false;
+
+	if (input == 0) {
+		input = aud_vfs_fopen(p_Filename, "rb");
+		if (input == 0) {
+			gchar* temp = g_strdup_printf("[xmms-musepack] mpcGetTuple is unable to open %s\n", p_Filename);
+			perror(temp);
+			g_free(temp);
+			return 0;
+		}
+		close_input = true;
+	}
+
+	tuple = aud_tuple_new_from_filename(p_Filename);
+
+	mpc_streaminfo info;
+	mpc_reader reader;
+	mpc_reader_setup_file_vfs(&reader, input);
+	mpc_demux * demux = mpc_demux_init(&reader);
+	mpc_demux_get_info(demux, &info);
+	mpc_demux_exit(demux);
+
+	aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, static_cast<int> (1000 * mpc_streaminfo_get_length(&info)));
+
+// 	gchar *scratch = g_strdup_printf("Musepack v%d (encoder %s)", info.stream_version, info.encoder);
+// 	aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, scratch);
+// 	g_free(scratch);
+
+// 	scratch = g_strdup_printf("lossy (%s)", info.profile_name);
+// 	aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, scratch);
+// 	g_free(scratch);
+
+	aud_tuple_associate_int(tuple, FIELD_BITRATE, NULL, static_cast<int> (info.average_bitrate / 1000));
+
+	MpcInfo tags = getTags(p_Filename);
+
+// 	aud_tuple_associate_string(tuple, FIELD_DATE, NULL, tags.date);
+// 	aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, tags.title);
+// 	aud_tuple_associate_string(tuple, FIELD_ARTIST, NULL, tags.artist);
+// 	aud_tuple_associate_string(tuple, FIELD_ALBUM, NULL, tags.album);
+// 	aud_tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, tags.track);
+// 	aud_tuple_associate_int(tuple, FIELD_YEAR, NULL, tags.year);
+// 	aud_tuple_associate_string(tuple, FIELD_GENRE, NULL, tags.genre);
+// 	aud_tuple_associate_string(tuple, FIELD_COMMENT, NULL, tags.comment);
+
+	freeTags(tags);
+
+	if (close_input)
+		aud_vfs_fclose(input);
+
+	return tuple;
+}
+
+static Tuple *mpcProbeForTuple(gchar* p_Filename, VFSFile *input)
+{
+    return mpcGetTuple(p_Filename, input);
+}
+
+static Tuple *mpcGetSongTuple(gchar* p_Filename)
+{
+	return mpcGetTuple(p_Filename, 0);
+}
+
+static char* mpcGenerateTitle(const MpcInfo& p_Tags, gchar* p_Filename)
+{
+    Tuple* tuple = mpcGetSongTuple(p_Filename);
+
+    gchar* title = aud_tuple_formatter_make_title_string(tuple, aud_get_gentitle_format());
+
+    aud_tuple_free((void *) tuple);
+    return title;
+}
+
+static void mpcGtkPrintLabel(GtkWidget* widget, const char* format,...)
+{
+    va_list args;
+
+    va_start(args, format);
+    gchar* temp = g_strdup_vprintf(format, args);
+    va_end(args);
+
+    gtk_label_set_text(GTK_LABEL(widget), temp);
+    g_free(temp);
+}
+
+static GtkWidget* mpcGtkTagLabel(const char* p_Text, int a, int b, int c, int d, GtkWidget* p_Box)
+{
+    GtkWidget* label = gtk_label_new(p_Text);
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(p_Box), label, a, b, c, d, GTK_FILL, GTK_FILL, 5, 5);
+    return label;
+}
+
+static GtkWidget* mpcGtkTagEntry(int a, int b, int c, int d, int p_Size, GtkWidget* p_Box)
+{
+    GtkWidget* entry;
+    entry = gtk_entry_new();
+    if(p_Size)
+        gtk_entry_set_max_length(GTK_ENTRY(entry), p_Size);
+
+    gtk_table_attach(GTK_TABLE(p_Box), entry, a, b, c, d,
+                    (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | GTK_SHRINK),
+                    (GtkAttachOptions) (GTK_FILL | GTK_EXPAND | GTK_SHRINK), 0, 5);
+    return entry;
+}
+
+static GtkWidget* mpcGtkLabel(GtkWidget* p_Box)
+{
+    GtkWidget* label = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(p_Box), label, FALSE, FALSE, 0);
+    return label;
+}
+
+static GtkWidget* mpcGtkButton(const char* p_Text, GtkWidget* p_Box)
+{
+    GtkWidget* button = gtk_button_new_with_label(p_Text);
+    GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(p_Box), button, TRUE, TRUE, 0);
+    return button;
+}
+
+static void mpcFileInfoBox(char* p_Filename)
+{
+    GtkWidget* infoBox = widgets.infoBox;
+
+    if(infoBox)
+        gdk_window_raise(infoBox->window);
+    else
+    {
+        infoBox = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+        gtk_window_set_type_hint(GTK_WINDOW(infoBox), GDK_WINDOW_TYPE_HINT_DIALOG);
+        widgets.infoBox = infoBox;
+        gtk_window_set_resizable(GTK_WINDOW(infoBox), FALSE);
+        g_signal_connect(G_OBJECT(infoBox), "destroy", G_CALLBACK(closeInfoBox), NULL);
+        gtk_container_set_border_width(GTK_CONTAINER(infoBox), 10);
+
+        GtkWidget* iVbox = gtk_vbox_new(FALSE, 10);
+        gtk_container_add(GTK_CONTAINER(infoBox), iVbox);
+
+        GtkWidget* filenameHbox = gtk_hbox_new(FALSE, 5);
+        gtk_box_pack_start(GTK_BOX(iVbox), filenameHbox, FALSE, TRUE, 0);
+
+        GtkWidget* fileLabel = gtk_label_new(_("Filename:"));
+        gtk_box_pack_start(GTK_BOX(filenameHbox), fileLabel, FALSE, TRUE, 0);
+
+        GtkWidget* fileEntry = gtk_entry_new();
+        widgets.fileEntry = fileEntry;
+        gtk_editable_set_editable(GTK_EDITABLE(fileEntry), FALSE);
+        gtk_box_pack_start(GTK_BOX(filenameHbox), fileEntry, TRUE, TRUE, 0);
+
+        GtkWidget* iHbox = gtk_hbox_new(FALSE, 10);
+        gtk_box_pack_start(GTK_BOX(iVbox), iHbox, FALSE, TRUE, 0);
+
+        GtkWidget* leftBox = gtk_vbox_new(FALSE, 10);
+        gtk_box_pack_start(GTK_BOX(iHbox), leftBox, FALSE, FALSE, 0);
+
+        //Tag labels
+        GtkWidget* tagFrame = gtk_frame_new(_("Musepack Tag"));
+        gtk_box_pack_start(GTK_BOX(leftBox), tagFrame, FALSE, FALSE, 0);
+        gtk_widget_set_sensitive(tagFrame, TRUE);
+
+        GtkWidget* iTable = gtk_table_new(5, 5, FALSE);
+        gtk_container_set_border_width(GTK_CONTAINER(iTable), 5);
+        gtk_container_add(GTK_CONTAINER(tagFrame), iTable);
+
+        mpcGtkTagLabel(_("Title:"), 0, 1, 0, 1, iTable);
+        GtkWidget* titleEntry = mpcGtkTagEntry(1, 4, 0, 1, 0, iTable);
+        widgets.titleEntry = titleEntry;
+
+        mpcGtkTagLabel(_("Artist:"), 0, 1, 1, 2, iTable);
+        GtkWidget* artistEntry = mpcGtkTagEntry(1, 4, 1, 2, 0, iTable);
+        widgets.artistEntry = artistEntry;
+
+        mpcGtkTagLabel(_("Album:"), 0, 1, 2, 3, iTable);
+        GtkWidget* albumEntry = mpcGtkTagEntry(1, 4, 2, 3, 0, iTable);
+        widgets.albumEntry = albumEntry;
+
+        mpcGtkTagLabel(_("Comment:"), 0, 1, 3, 4, iTable);
+        GtkWidget* commentEntry = mpcGtkTagEntry(1, 4, 3, 4, 0, iTable);
+        widgets.commentEntry = commentEntry;
+
+        mpcGtkTagLabel(_("Year:"), 0, 1, 4, 5, iTable);
+        GtkWidget* yearEntry = mpcGtkTagEntry(1, 2, 4, 5, 4, iTable);
+        widgets.yearEntry = yearEntry;
+        gtk_widget_set_size_request(yearEntry, 4, -1);
+
+        mpcGtkTagLabel(_("Track:"), 2, 3, 4, 5, iTable);
+        GtkWidget* trackEntry = mpcGtkTagEntry(3, 4, 4, 5, 4, iTable);
+        widgets.trackEntry = trackEntry;
+        gtk_widget_set_size_request(trackEntry, 3, -1);
+
+        mpcGtkTagLabel(_("Genre:"), 0, 1, 5, 6, iTable);
+        GtkWidget* genreEntry = mpcGtkTagEntry(1, 4, 5, 6, 0, iTable);
+        widgets.genreEntry = genreEntry;
+        gtk_widget_set_size_request(genreEntry, 20, -1);
+
+        //Buttons
+        GtkWidget* buttonBox = gtk_hbutton_box_new();
+        gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END);
+        gtk_box_set_spacing(GTK_BOX(buttonBox), 5);
+        gtk_box_pack_start(GTK_BOX(leftBox), buttonBox, FALSE, FALSE, 0);
+
+        GtkWidget* saveButton = mpcGtkButton(_("Save"), buttonBox);
+        g_signal_connect(G_OBJECT(saveButton), "clicked", G_CALLBACK(saveTags), NULL);
+
+        GtkWidget* removeButton = mpcGtkButton(_("Remove Tag"), buttonBox);
+        g_signal_connect_swapped(G_OBJECT(removeButton), "clicked", G_CALLBACK(removeTags), NULL);
+
+        GtkWidget* cancelButton = mpcGtkButton(_("Cancel"), buttonBox);
+        g_signal_connect_swapped(G_OBJECT(cancelButton), "clicked", G_CALLBACK(closeInfoBox), NULL);
+        gtk_widget_grab_default(cancelButton);
+
+        //File information
+        GtkWidget* infoFrame = gtk_frame_new(_("Musepack Info"));
+        gtk_box_pack_start(GTK_BOX(iHbox), infoFrame, FALSE, FALSE, 0);
+
+        GtkWidget* infoVbox = gtk_vbox_new(FALSE, 5);
+        gtk_container_add(GTK_CONTAINER(infoFrame), infoVbox);
+        gtk_container_set_border_width(GTK_CONTAINER(infoVbox), 10);
+        gtk_box_set_spacing(GTK_BOX(infoVbox), 0);
+
+        GtkWidget* streamLabel    = mpcGtkLabel(infoVbox);
+        GtkWidget* encoderLabel   = mpcGtkLabel(infoVbox);
+        GtkWidget* profileLabel   = mpcGtkLabel(infoVbox);
+		GtkWidget* pnsLabel       = mpcGtkLabel(infoVbox);
+		GtkWidget* gaplessLabel   = mpcGtkLabel(infoVbox);
+        GtkWidget* bitrateLabel   = mpcGtkLabel(infoVbox);
+        GtkWidget* rateLabel      = mpcGtkLabel(infoVbox);
+        GtkWidget* channelsLabel  = mpcGtkLabel(infoVbox);
+        GtkWidget* lengthLabel    = mpcGtkLabel(infoVbox);
+        GtkWidget* fileSizeLabel  = mpcGtkLabel(infoVbox);
+        GtkWidget* trackPeakLabel = mpcGtkLabel(infoVbox);
+        GtkWidget* trackGainLabel = mpcGtkLabel(infoVbox);
+        GtkWidget* albumPeakLabel = mpcGtkLabel(infoVbox);
+        GtkWidget* albumGainLabel = mpcGtkLabel(infoVbox);
+
+        VFSFile *input = aud_vfs_fopen(p_Filename, "rb");
+        if(input)
+        {
+            mpc_streaminfo info;
+            mpc_reader reader;
+            mpc_reader_setup_file_vfs(&reader, input);
+			mpc_demux * demux = mpc_demux_init(&reader);
+			mpc_demux_get_info(demux, &info);
+			mpc_demux_exit(demux);
+
+            gint time = static_cast<int> (mpc_streaminfo_get_length(&info));
+            gint minutes = time / 60;
+            gint seconds = time % 60;
+
+			mpcGtkPrintLabel(streamLabel,    _("Streamversion %d"), info.stream_version);
+			mpcGtkPrintLabel(encoderLabel,   _("Encoder: \%s"), info.encoder);
+			mpcGtkPrintLabel(profileLabel,   _("Profile: \%s (q=%0.2f)"), info.profile_name, info.profile - 5);
+			mpcGtkPrintLabel(pnsLabel,       _("PNS: \%s"), info.pns == 0xFF ? _("unknow") : info.pns ? _("on") : _("off"));
+			mpcGtkPrintLabel(gaplessLabel,   _("Gapless: \%s"), info.is_true_gapless ? _("on") : _("off"));
+			mpcGtkPrintLabel(bitrateLabel,   _("Average bitrate: \%6.1f kbps"), info.average_bitrate * 1.e-3);
+			mpcGtkPrintLabel(rateLabel,      _("Samplerate: \%d Hz"), info.sample_freq);
+			mpcGtkPrintLabel(channelsLabel,  _("Channels: \%d"), info.channels);
+			mpcGtkPrintLabel(lengthLabel,    _("Length: \%d:\%.2d (%u samples)"), minutes, seconds, (mpc_uint32_t)mpc_streaminfo_get_length_samples(&info));
+			mpcGtkPrintLabel(fileSizeLabel,  _("File size: \%d Bytes"), info.total_file_length);
+			mpcGtkPrintLabel(trackPeakLabel, _("Track Peak: \%2.2f dB"), info.peak_title / 256.);
+			mpcGtkPrintLabel(trackGainLabel, _("Track Gain: \%2.2f dB"), info.gain_title / 256.);
+			mpcGtkPrintLabel(albumPeakLabel, _("Album Peak: \%2.2f dB"), info.peak_album / 256.);
+			mpcGtkPrintLabel(albumGainLabel, _("Album Gain: \%2.2f dB"), info.gain_album / 256.);
+
+            MpcInfo tags = getTags(p_Filename);
+            gtk_entry_set_text(GTK_ENTRY(titleEntry),   tags.title);
+            gtk_entry_set_text(GTK_ENTRY(artistEntry),  tags.artist);
+            gtk_entry_set_text(GTK_ENTRY(albumEntry),   tags.album);
+            gtk_entry_set_text(GTK_ENTRY(commentEntry), tags.comment);
+            gtk_entry_set_text(GTK_ENTRY(genreEntry),   tags.genre);
+            gchar* entry = g_strdup_printf ("%d", tags.track);
+            gtk_entry_set_text(GTK_ENTRY(trackEntry), entry);
+            g_free(entry);
+            entry = g_strdup_printf ("%d", tags.year);
+            gtk_entry_set_text(GTK_ENTRY(yearEntry), entry);
+            g_free(entry);
+            entry = g_filename_display_name(p_Filename);
+            gtk_entry_set_text(GTK_ENTRY(fileEntry), entry);
+            g_free(entry);
+            freeTags(tags);
+            aud_vfs_fclose(input);
+        }
+        else
+        {
+            gchar* temp = g_strdup_printf("[xmms-musepack] mpcFileInfoBox is unable to read tags from %s", p_Filename);
+            perror(temp);
+            g_free(temp);
+        }
+
+	gchar* name = g_filename_display_basename(p_Filename);
+        gchar* text = g_strdup_printf(_("File Info - %s"), name);
+        g_free(name);
+        gtk_window_set_title(GTK_WINDOW(infoBox), text);
+        g_free(text);
+
+        gtk_widget_show_all(infoBox);
+    }
+}
+
+static void closeInfoBox(GtkWidget* w, gpointer data)
+{
+    gtk_widget_destroy(widgets.infoBox);
+    widgets.infoBox = NULL;
+}
+
+static void* endThread(gchar* p_FileName, VFSFile * p_FileHandle, bool release)
+{
+    if(release)
+        lockRelease();
+    if(mpcDecoder.isError)
+    {
+        perror(mpcDecoder.isError);
+        g_free(mpcDecoder.isError);
+        mpcDecoder.isError = NULL;
+    }
+    mpcDecoder.isAlive = false;
+    if(p_FileHandle)
+        aud_vfs_fclose(p_FileHandle);
+    if(track.display)
+    {
+        g_free(track.display);
+        track.display = NULL;
+    }
+    return 0;
+}
+
+static int processBuffer(InputPlayback *playback,
+    MPC_SAMPLE_FORMAT* sampleBuffer, char* xmmsBuffer, mpc_demux* demux)
+{
+	mpc_frame_info info;
+
+	info.buffer = sampleBuffer;
+	mpc_demux_decode(demux, &info);
+
+	if (info.bits == -1) return -1; // end of stream
+
+	copyBuffer(sampleBuffer, xmmsBuffer, info.samples * track.channels);
+
+    if (pluginConfig.dynamicBitrate)
+    {
+		track.bitrate = static_cast<int> (info.bits * track.sampleFreq / 1152);
+    }
+
+	playback->pass_audio(playback, FMT_S16_LE, track.channels, info.samples * 2 * track.channels, xmmsBuffer, NULL);
+	return info.samples;
+}
+
+static void* decodeStream(InputPlayback *data)
+{
+    lockAcquire();
+    gchar* filename = data->filename;
+    VFSFile *input = aud_vfs_fopen(filename, "rb");
+    if (!input)
+    {
+        mpcDecoder.isError = g_strdup_printf("[xmms-musepack] decodeStream is unable to open %s", filename);
+        return endThread(filename, input, true);
+    }
+
+    mpc_reader reader;
+    mpc_reader_setup_file_vfs(&reader, input);
+
+	mpc_demux * demux = mpc_demux_init(&reader);
+	if (demux == 0)
+	{
+		mpcDecoder.isError = g_strdup_printf("[xmms-musepack] decodeStream is unable to initialize demuxer on %s", filename);
+		return endThread(filename, input, true);
+	}
+
+    mpc_streaminfo info;
+	mpc_demux_get_info(demux, &info);
+
+    MpcInfo tags     = getTags(filename);
+    track.display    = mpcGenerateTitle(tags, filename);
+    track.length     = static_cast<int> (1000 * mpc_streaminfo_get_length(&info));
+    track.bitrate    = static_cast<int> (info.average_bitrate);
+    track.sampleFreq = info.sample_freq;
+    track.channels   = info.channels;
+    freeTags(tags);
+
+    data->set_params(data, track.display, track.length, track.bitrate, track.sampleFreq, track.channels);
+
+	mpc_set_replay_level(demux, MPC_OLD_GAIN_REF, pluginConfig.replaygain,
+						 pluginConfig.albumGain, pluginConfig.clipPrevention);
+
+    MPC_SAMPLE_FORMAT sampleBuffer[MPC_DECODER_BUFFER_LENGTH];
+    char xmmsBuffer[MPC_DECODER_BUFFER_LENGTH * 4];
+
+    if (!data->output->open_audio(FMT_S16_LE, track.sampleFreq, track.channels))
+    {
+        mpcDecoder.isError = g_strdup_printf("[xmms-musepack] decodeStream is unable to open an audio output");
+        return endThread(filename, input, true);
+    }
+
+	mpcDecoder.isOutput = true;
+    lockRelease();
+
+	data->set_pb_ready(data);
+	data->playing = TRUE;
+
+    gint counter = 2 * track.sampleFreq / 3;
+	int status = 0;
+    while (mpcDecoder.isAlive)
+    {
+        lockAcquire();
+
+		if (mpcDecoder.offset != -1)
+        {
+			mpc_demux_seek_sample(demux, mpcDecoder.offset * track.sampleFreq / 1000);
+			data->output->flush(mpcDecoder.offset);
+            mpcDecoder.offset = -1;
+        }
+
+        short iPlaying = data->output->buffer_playing()? 1 : 0;
+        gint iFree = data->output->buffer_free();
+        if (!mpcDecoder.isPause && iFree >= ((1152 * 4) << iPlaying) && status != -1)
+        {
+            status = processBuffer(data, sampleBuffer, xmmsBuffer, demux);
+            lockRelease();
+
+            if(pluginConfig.dynamicBitrate)
+            {
+                counter -= status;
+                if(counter < 0)
+                {
+                    data->set_params(data, track.display, track.length, track.bitrate, track.sampleFreq, track.channels);
+                    counter = 2 * track.sampleFreq / 3;
+                }
+            }
+        }
+        else
+        {
+            lockRelease();
+			if (mpcDecoder.isPause == FALSE && status == -1 &&
+						 data->output->buffer_playing() == FALSE)
+				break;
+            g_usleep(60000);
+        }
+    }
+	mpc_demux_exit(demux);
+    return endThread(filename, input, false);
+}
+
+const gchar *mpc_fmts[] = { "mpc", NULL };
+
+InputPlugin MpcPlugin = {
+	0, // handle
+	0, // filename
+    (gchar *)"Musepack Audio Plugin", // description
+    mpcOpenPlugin, // init
+	0, // cleanup
+    mpcAboutBox, // about : Show About box
+    mpcConfigBox, // configure : Show Configure box
+    TRUE, // enabled
+	0, // is_our_file
+	0, // scan_dir
+    mpcPlay, // play_file
+    mpcStop, // stop
+    mpcPause, // pause
+    mpcSeek, // seek
+	0, // get_time
+	0, // get_volume
+	0, // set_volume
+	0, // get_vis_type
+	0, // add_vis_pcm
+	0, // set_info
+	0, // set_info_text
+	0, // get_song_info : Get Title String callback
+    mpcFileInfoBox, // file_info_box : Show File Info Box
+    mpcGetSongTuple, // get_song_tuple : Acquire tuple for song
+    mpcIsOurFD, // is_our_file_from_vfs
+    (gchar **)mpc_fmts, // vfs_extensions
+
+    /* Added in Audacious 1.4.0 */
+	mpcSeekm, // void (*mseek) (InputPlayback * playback, gulong millisecond);
+	mpcProbeForTuple, // Tuple *(*probe_for_tuple)(gchar *uri, VFSFile *fd);
+
+    /* Added in Audacious 1.4.1 */
+//     gboolean have_subtune;
+
+    /* Added in Audacious 1.5.0 */
+//     gboolean (*update_song_tuple)(Tuple *tuple, VFSFile *fd);
+};
+
+InputPlugin *mpc_iplist[] = { &MpcPlugin, NULL };
+
+DECLARE_PLUGIN(musepack, NULL, NULL, mpc_iplist, NULL, NULL, NULL, NULL,NULL);
Index: /bmp-musepack/trunk/libmpc.h
===================================================================
--- /bmp-musepack/trunk/libmpc.h	(revision 456)
+++ /bmp-musepack/trunk/libmpc.h	(revision 456)
@@ -0,0 +1,132 @@
+#ifndef XMMS_MUSEPACK
+#define XMMS_MUSEPACK
+
+//xmms headers
+extern "C"
+{
+#include <audacious/plugin.h>
+#include <audacious/output.h>
+#include <audacious/i18n.h>
+}
+
+//stdlib headers
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+//libmpcdec headers
+#include <mpc/mpcdec.h>
+
+//GTK+ headers
+#include <glib.h>
+#include <gtk/gtk.h>
+
+//taglib headers
+#include <taglib/tag.h>
+#include <taglib/apetag.h>
+#include <taglib/mpcfile.h>
+
+struct PluginConfig
+{
+    gboolean clipPrevention;
+    gboolean dynamicBitrate;
+    gboolean replaygain;
+    gboolean albumGain;
+};
+
+struct Widgets
+{
+    GtkWidget* aboutBox;
+    GtkWidget* configBox;
+    GtkWidget* bitrateCheck;
+    GtkWidget* clippingCheck;
+    GtkWidget* replaygainCheck;
+    GtkWidget* albumCheck;
+    GtkWidget* infoBox;
+    GtkWidget* albumEntry;
+    GtkWidget* artistEntry;
+    GtkWidget* titleEntry;
+    GtkWidget* genreEntry;
+    GtkWidget* yearEntry;
+    GtkWidget* trackEntry;
+    GtkWidget* commentEntry;
+    GtkWidget* fileEntry;
+};
+
+struct MpcDecoder
+{
+    gchar*     isError;
+    long long  offset;
+    bool       isOutput;
+    bool       isAlive;
+    bool       isPause;
+};
+
+struct TrackInfo
+{
+    gint   bitrate;
+    gchar* display;
+    gint   length;
+    gint   sampleFreq;
+    gint   channels;
+};
+
+struct MpcInfo
+{
+    gchar*    title;
+    gchar*    artist;
+    gchar*    album;
+    gchar*    comment;
+    gchar*    genre;
+    gchar*    date;
+    unsigned  track;
+    unsigned  year;
+};
+
+static void       toggleSwitch(GtkWidget*, gpointer);
+static void       saveConfigBox(GtkWidget*, gpointer);
+static void       closeInfoBox(GtkWidget*, gpointer);
+static void*      decodeStream(InputPlayback*);
+
+#ifdef MPC_FIXED_POINT
+inline static int shiftSigned(MPC_SAMPLE_FORMAT val, int shift)
+{
+    if (shift > 0)
+        val <<= shift;
+    else if (shift < 0)
+        val >>= -shift;
+    return (int) val;
+}
+#endif
+
+inline static void copyBuffer(MPC_SAMPLE_FORMAT* pInBuf, char* pOutBuf, unsigned pLength)
+{
+    unsigned pSize = 16;
+    int clipMin    = -1 << (pSize - 1);
+    int clipMax    = (1 << (pSize - 1)) - 1;
+    int floatScale =  1 << (pSize - 1);
+    for (unsigned n = 0; n < 2 * pLength; n++)
+    {
+        int val;
+#ifdef MPC_FIXED_POINT
+        val = shiftSigned(pInBuf[n], pSize - MPC_FIXED_POINT_SCALE_SHIFT);
+#else
+        val = (int) (pInBuf[n] * floatScale);
+#endif
+        if (val < clipMin)
+            val = clipMin;
+        else if (val > clipMax)
+            val = clipMax;
+        unsigned shift = 0;
+        do
+        {
+            pOutBuf[n * 2 + (shift / 8)] = (unsigned char) ((val >> shift) & 0xFF);
+            shift += 8;
+        }
+        while (shift < pSize);
+    }
+}
+
+#endif
