Index: bmp-musepack/trunk/libmpc.cpp
===================================================================
--- bmp-musepack/trunk/src/libmpc.cpp	(revision 455)
+++ bmp-musepack/trunk/libmpc.cpp	(revision 456)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2005, The Musepack Development Team
+ * Copyright (c) 2005-2009, The Musepack Development Team
  * All rights reserved.
  *
@@ -33,8 +33,10 @@
  */
 
+
 #include "libmpc.h"
 
-#define FORCED_THREAD_STACKSIZE 1024 * 1000
-
+#define REMOVE_NONEXISTANT_TAG(x)   if (!*x) { x = NULL; }
+#define VERSION "1.3"
+#define PACKAGE "aud_mpc"
 
 using TagLib::MPC::File;
@@ -43,38 +45,4 @@
 using TagLib::APE::ItemListMap;
 
-InputPlugin MpcPlugin = {
-    NULL,           //File Handle               FILE* handle
-    NULL,           //Filename                  char* filename
-    NULL,           //Name of Plugin            char* filename
-    mpcOpenPlugin,  //Open Plugin               [CALLBACK]
-    mpcAboutBox,    //Show About box            [CALLBACK]
-    mpcConfigBox,   //Show Configure box        [CALLBACK]
-    mpcIsOurFile,   //Check if it's our file    [CALLBACK]
-    NULL,           //Scan the directory        [UNUSED]
-    mpcPlay,        //Play                      [CALLBACK]
-    mpcStop,        //Stop                      [CALLBACK]
-    mpcPause,       //Pause                     [CALLBACK]
-    mpcSeek,        //Seek                      [CALLBACK]
-    mpcSetEq,       //Set EQ                    [CALLBACK]
-    mpcGetTime,     //Get Time                  [CALLBACK]
-    NULL,           //Get Volume                [UNUSED]
-    NULL,           //Set Volume                [UNUSED]
-    mpcClosePlugin, //Close Plugin              [CALLBACK]
-    NULL,           //Obsolete                  [UNUSED]
-    NULL,           //Visual plugins            add_vis_pcm(int time, AFormat fmt, int nch, int length, void *ptr)
-    NULL,           //Set Info Settings         set_info(char *title, int length, int rate, int freq, int nch)
-    NULL,           //set Info Text             set_info_text(char* text)
-    mpcGetSongInfo, //Get Title String callback [CALLBACK]
-    mpcFileInfoBox, //Show File Info Box        [CALLBACK]
-    NULL,           //Output Plugin Handle      OutputPlugin output
-};
-
-extern "C"
-InputPlugin* get_iplugin_info()
-{
-    MpcPlugin.description = g_strdup_printf("Musepack Audio Plugin %s", VERSION);
-    return &MpcPlugin;
-}
-
 static PluginConfig pluginConfig = {0};
 static Widgets      widgets      = {0};
@@ -82,23 +50,81 @@
 static TrackInfo    track        = {0};
 
-static pthread_t           threadHandle;
-static pthread_attr_t      threadAttr;
-static pthread_mutex_t     threadMutex;
-static pthread_mutexattr_t threadMutexAttr;
+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()
 {
-    pthread_mutexattr_init(&threadMutexAttr);
-    pthread_mutex_init(&threadMutex, &threadMutexAttr);
-    pthread_attr_init(&threadAttr);
-    pthread_attr_setstacksize(&threadAttr, FORCED_THREAD_STACKSIZE);
-
-    ConfigDb *cfg;
-    cfg = bmp_cfg_db_open();
-    bmp_cfg_db_get_bool(cfg, "musepack", "clipPrevention", &pluginConfig.clipPrevention);
-    bmp_cfg_db_get_bool(cfg, "musepack", "albumGain",      &pluginConfig.albumGain);
-    bmp_cfg_db_get_bool(cfg, "musepack", "dynamicBitrate", &pluginConfig.dynamicBitrate);
-    bmp_cfg_db_get_bool(cfg, "musepack", "replaygain",     &pluginConfig.replaygain);
-    bmp_cfg_db_close(cfg);
+    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);
 }
 
@@ -110,11 +136,16 @@
     else
     {
-        char* titleText      = g_strdup_printf("Musepack Decoder Plugin %s", VERSION);
-        const char* contentText = "Plugin code by\nBenoit Amiaux\nMartin Spuler\nKuniklo\n\nGet latest version at http://musepack.net\n";
-	    const char* buttonText  = "Nevermind";
-        aboutBox = xmms_show_message(titleText, contentText, buttonText, FALSE, NULL, NULL);
+        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;
-        gtk_signal_connect(GTK_OBJECT(aboutBox), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &widgets.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)));
 }
 
@@ -129,8 +160,8 @@
         gtk_window_set_type_hint(GTK_WINDOW(configBox), GDK_WINDOW_TYPE_HINT_DIALOG);
         widgets.configBox = configBox;
-        gtk_signal_connect(GTK_OBJECT(configBox), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &widgets.configBox);
-        gtk_window_set_title(GTK_WINDOW(configBox), "Musepack Decoder Configuration");
-        gtk_window_set_policy(GTK_WINDOW(configBox), FALSE, FALSE, FALSE);
-        gtk_container_border_width(GTK_CONTAINER(configBox), 10);
+        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();
@@ -140,38 +171,38 @@
 
         //General Settings Tab
-        GtkWidget* generalSet = gtk_frame_new("General Settings");
-        gtk_container_border_width(GTK_CONTAINER(generalSet), 5);
+        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_border_width(GTK_CONTAINER(gSvbox), 5);
+        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");
+        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"));
+        gtk_notebook_append_page(GTK_NOTEBOOK(notebook), generalSet, gtk_label_new(_("Plugin")));
 
         //ReplayGain Settings Tab
-        GtkWidget* replaygainSet = gtk_frame_new("ReplayGain Settings");
-        gtk_container_border_width(GTK_CONTAINER(replaygainSet), 5);
+        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_border_width(GTK_CONTAINER(rSVbox), 5);
+        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");
+        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");
+        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");
+        GtkWidget* replaygainType = gtk_frame_new(_("ReplayGain Type"));
         gtk_box_pack_start(GTK_BOX(rSVbox), replaygainType, FALSE, FALSE, 0);
-        gtk_signal_connect(GTK_OBJECT(replaygainCheck), "toggled", GTK_SIGNAL_FUNC(toggleSwitch), replaygainType);
+        g_signal_connect(G_OBJECT(replaygainCheck), "toggled", G_CALLBACK(toggleSwitch), replaygainType);
 
         GtkWidget* rgVbox = gtk_vbox_new(FALSE, 5);
@@ -179,28 +210,28 @@
         gtk_container_add(GTK_CONTAINER(replaygainType), rgVbox);
 
-        GtkWidget* trackCheck = gtk_radio_button_new_with_label(NULL, "Use Track Gain");
+        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_group(GTK_RADIO_BUTTON(trackCheck)), "Use Album Gain");
+        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"));
+        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_button_box_set_spacing(GTK_BUTTON_BOX(buttonBox), 5);
+        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");
-        gtk_signal_connect(GTK_OBJECT(okButton), "clicked", GTK_SIGNAL_FUNC(saveConfigBox), NULL);
+        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");
-        gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(widgets.configBox));
+        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);
@@ -211,12 +242,7 @@
 }
 
-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 saveConfigBox(GtkWidget* p_Widget, gpointer p_Data)
 {
-    ConfigDb* cfg;
+    mcs_handle_t* cfg;
     GtkToggleButton* tb;
 
@@ -230,26 +256,28 @@
     pluginConfig.albumGain = gtk_toggle_button_get_active(tb);
 
-    cfg = bmp_cfg_db_open();
-
-    bmp_cfg_db_set_bool(cfg, "musepack", "clipPrevention", pluginConfig.clipPrevention);
-    bmp_cfg_db_set_bool(cfg, "musepack", "albumGain",      pluginConfig.albumGain);
-    bmp_cfg_db_set_bool(cfg, "musepack", "dynamicBitrate", pluginConfig.dynamicBitrate);
-    bmp_cfg_db_set_bool(cfg, "musepack", "replaygain",     pluginConfig.replaygain);
-
-    bmp_cfg_db_close(cfg);
+    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 int mpcIsOurFile(char* p_Filename)
-{
-    char* ext;
-    ext = strrchr(p_Filename, '.');
-    if(ext)
-        return !(strcasecmp(ext, ".mpc") && strcasecmp(ext, ".mpp") && strcasecmp(ext, ".mp+"));
-    return FALSE;
-}
-
-static void mpcPlay(char* p_Filename)
+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;
@@ -257,17 +285,18 @@
     mpcDecoder.isOutput = false;
     mpcDecoder.isPause  = false;
-    pthread_create(&threadHandle, &threadAttr, decodeStream, (void *) g_strdup(p_Filename));
-}
-
-static void mpcStop()
-{
-    setAlive(false);
+    threadHandle = g_thread_self();
+    decodeStream(data);
+}
+
+static void mpcStop(InputPlayback *data)
+{
+    mpcDecoder.isAlive = false;
     if (threadHandle)
     {
-        pthread_join(threadHandle, NULL);
+        g_thread_join(threadHandle);
         if (mpcDecoder.isOutput)
         {
-            MpcPlugin.output->buffer_free();
-            MpcPlugin.output->close_audio();
+            data->output->buffer_free();
+            data->output->close_audio();
             mpcDecoder.isOutput = false;
         }
@@ -275,82 +304,54 @@
 }
 
-static void mpcPause(short p_Pause)
+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;
-    MpcPlugin.output->pause(p_Pause);
+    data->output->pause(p_Pause);
     lockRelease();
 }
 
-static void mpcSeek(int p_Offset)
+static void mpcSeekm(InputPlayback *data, gulong ms_offset)
 {
     lockAcquire();
-    mpcDecoder.offset = static_cast<double> (p_Offset);
-    MpcPlugin.output->flush(1000 * p_Offset);
+    mpcDecoder.offset = ms_offset;
     lockRelease();
 }
 
-static void mpcSetEq(int on, float preamp, float* eq)
-{
-    pluginConfig.isEq = static_cast<bool> (on);
-    init_iir(on, preamp, eq);
-}
-
-static int mpcGetTime()
-{
-    if(!isAlive())
-        return -1;
-    return MpcPlugin.output->output_time();
-}
-
-static void mpcClosePlugin()
-{
-    pthread_mutex_destroy(&threadMutex);
-    pthread_mutexattr_destroy(&threadMutexAttr);
-    pthread_attr_destroy(&threadAttr);
-}
-
-static void mpcGetSongInfo(char* p_Filename, char** p_Title, int* p_Length)
-{
-	mpc_reader reader;
-	mpc_demux * demux;
-	if (mpc_reader_init_stdio(&reader, p_Filename) == MPC_STATUS_OK && (demux = mpc_demux_init(&reader))) {
-        MpcInfo tags = getTags(p_Filename);
-        *p_Title = mpcGenerateTitle(tags, p_Filename);
-        freeTags(tags);
-		mpc_streaminfo info;
-		mpc_demux_get_info(demux, &info);
-		*p_Length = static_cast<int> (1000 * mpc_streaminfo_get_length(&info));
-		mpc_demux_exit(demux);
-		mpc_reader_exit_stdio(&reader);
-    } else {
-        char* temp = g_strdup_printf("[xmms-musepack] mpcGetSongInfo is unable to open %s\n", p_Filename);
-        perror(temp);
-        free(temp);
-    }
-}
-
-static void freeTags(MpcInfo& tags)
-{
-    free(tags.title);
-    free(tags.artist);
-    free(tags.album);
-    free(tags.comment);
-    free(tags.genre);
-    free(tags.date);
-}
-
-static MpcInfo getTags(const char* p_Filename)
-{
-    File oFile(p_Filename, false);
+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)
@@ -366,5 +367,185 @@
         }
     }
+#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;
 }
 
@@ -380,6 +561,6 @@
         gtk_window_set_type_hint(GTK_WINDOW(infoBox), GDK_WINDOW_TYPE_HINT_DIALOG);
         widgets.infoBox = infoBox;
-        gtk_window_set_policy(GTK_WINDOW(infoBox), FALSE, FALSE, FALSE);
-        gtk_signal_connect(GTK_OBJECT(infoBox), "destroy", GTK_SIGNAL_FUNC(closeInfoBox), NULL);
+        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);
 
@@ -390,5 +571,5 @@
         gtk_box_pack_start(GTK_BOX(iVbox), filenameHbox, FALSE, TRUE, 0);
 
-        GtkWidget* fileLabel = gtk_label_new("Filename:");
+        GtkWidget* fileLabel = gtk_label_new(_("Filename:"));
         gtk_box_pack_start(GTK_BOX(filenameHbox), fileLabel, FALSE, TRUE, 0);
 
@@ -405,5 +586,5 @@
 
         //Tag labels
-        GtkWidget* tagFrame = gtk_frame_new("Musepack Tag");
+        GtkWidget* tagFrame = gtk_frame_new(_("Musepack Tag"));
         gtk_box_pack_start(GTK_BOX(leftBox), tagFrame, FALSE, FALSE, 0);
         gtk_widget_set_sensitive(tagFrame, TRUE);
@@ -413,53 +594,53 @@
         gtk_container_add(GTK_CONTAINER(tagFrame), iTable);
 
-        mpcGtkTagLabel("Title:", 0, 1, 0, 1, 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);
+        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);
+        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);
+        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);
+        mpcGtkTagLabel(_("Year:"), 0, 1, 4, 5, iTable);
         GtkWidget* yearEntry = mpcGtkTagEntry(1, 2, 4, 5, 4, iTable);
         widgets.yearEntry = yearEntry;
-        gtk_widget_set_usize(yearEntry, 4, -1);
-
-        mpcGtkTagLabel("Track:", 2, 3, 4, 5, iTable);
+        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_usize(trackEntry, 3, -1);
-
-        mpcGtkTagLabel("Genre:", 0, 1, 5, 6, iTable);
+        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_usize(genreEntry, 20, -1);
+        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_button_box_set_spacing(GTK_BUTTON_BOX(buttonBox), 5);
+        gtk_box_set_spacing(GTK_BOX(buttonBox), 5);
         gtk_box_pack_start(GTK_BOX(leftBox), buttonBox, FALSE, FALSE, 0);
 
-        GtkWidget* saveButton = mpcGtkButton("Save", buttonBox);
-        gtk_signal_connect(GTK_OBJECT(saveButton), "clicked", GTK_SIGNAL_FUNC(saveTags), NULL);
-
-        GtkWidget* removeButton = mpcGtkButton("Remove Tag", buttonBox);
-        gtk_signal_connect_object(GTK_OBJECT(removeButton), "clicked", GTK_SIGNAL_FUNC(removeTags), NULL);
-
-        GtkWidget* cancelButton = mpcGtkButton("Cancel", buttonBox);
-        gtk_signal_connect_object(GTK_OBJECT(cancelButton), "clicked", GTK_SIGNAL_FUNC(closeInfoBox), NULL);
+        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");
+        GtkWidget* infoFrame = gtk_frame_new(_("Musepack Info"));
         gtk_box_pack_start(GTK_BOX(iHbox), infoFrame, FALSE, FALSE, 0);
 
@@ -471,5 +652,5 @@
         GtkWidget* streamLabel    = mpcGtkLabel(infoVbox);
         GtkWidget* encoderLabel   = mpcGtkLabel(infoVbox);
-		GtkWidget* profileLabel   = mpcGtkLabel(infoVbox);
+        GtkWidget* profileLabel   = mpcGtkLabel(infoVbox);
 		GtkWidget* pnsLabel       = mpcGtkLabel(infoVbox);
 		GtkWidget* gaplessLabel   = mpcGtkLabel(infoVbox);
@@ -484,28 +665,32 @@
         GtkWidget* albumGainLabel = mpcGtkLabel(infoVbox);
 
-		mpc_reader reader;
-		mpc_demux * demux;
-		if (mpc_reader_init_stdio(&reader, p_Filename) == MPC_STATUS_OK && (demux = mpc_demux_init(&reader))) {
+        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);
-
-            int time = static_cast<int> (mpc_streaminfo_get_length(&info));
-            int minutes = time / 60;
-            int 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.);
+			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);
@@ -515,125 +700,31 @@
             gtk_entry_set_text(GTK_ENTRY(commentEntry), tags.comment);
             gtk_entry_set_text(GTK_ENTRY(genreEntry),   tags.genre);
-            char* entry = g_strdup_printf ("%d", tags.track);
+            gchar* entry = g_strdup_printf ("%d", tags.track);
             gtk_entry_set_text(GTK_ENTRY(trackEntry), entry);
-            free(entry);
+            g_free(entry);
             entry = g_strdup_printf ("%d", tags.year);
             gtk_entry_set_text(GTK_ENTRY(yearEntry), entry);
-            free(entry);
+            g_free(entry);
             entry = g_filename_display_name(p_Filename);
             gtk_entry_set_text(GTK_ENTRY(fileEntry), entry);
-            free(entry);
+            g_free(entry);
             freeTags(tags);
-			mpc_demux_exit(demux);
-			mpc_reader_exit_stdio(&reader);
+            aud_vfs_fclose(input);
         }
         else
         {
-            char* temp = g_strdup_printf("[xmms-musepack] mpcFileInfoBox is unable to read tags from %s", p_Filename);
+            gchar* temp = g_strdup_printf("[xmms-musepack] mpcFileInfoBox is unable to read tags from %s", p_Filename);
             perror(temp);
-            free(temp);
+            g_free(temp);
         }
 
-	char* name = g_filename_display_basename(p_Filename);
-        char* text = g_strdup_printf("File Info - %s", name);
-        free(name);
+	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);
-        free(text);
+        g_free(text);
 
         gtk_widget_show_all(infoBox);
     }
-}
-
-static void mpcGtkPrintLabel(GtkWidget* widget, char* format,...)
-{
-    va_list args;
-
-    va_start(args, format);
-    char* temp = g_strdup_vprintf(format, args);
-    va_end(args);
-
-    gtk_label_set_text(GTK_LABEL(widget), temp);
-    free(temp);
-}
-
-static GtkWidget* mpcGtkTagLabel(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;
-    if(p_Size == 0)
-        entry = gtk_entry_new();
-    else
-        entry = gtk_entry_new_with_max_length(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(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 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();
-
-    char* cAlbum   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.albumEntry)));
-    char* cArtist  = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.artistEntry)));
-    char* cTitle   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.titleEntry)));
-    char* cGenre   = g_strdup(gtk_entry_get_text(GTK_ENTRY(widgets.genreEntry)));
-    char* 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))));
-
-    free(cAlbum);
-    free(cArtist);
-    free(cTitle);
-    free(cGenre);
-    free(cComment);
-
-    oFile.save();
-    closeInfoBox(NULL, NULL);
 }
 
@@ -644,46 +735,6 @@
 }
 
-static char* mpcGenerateTitle(const MpcInfo& p_Tags, const char* p_Filename)
-{
-    TitleInput* input;
-    //From titlestring.h
-    input            = g_new0(TitleInput, 1);
-    input->__size    = XMMS_TITLEINPUT_SIZE;
-    input->__version = XMMS_TITLEINPUT_VERSION;
-    //end
-
-    input->file_name    = g_filename_display_basename(p_Filename);
-    input->file_path    = g_path_get_dirname(p_Filename);
-    input->file_ext     = "mpc";
-    input->date         = g_strdup(p_Tags.date);
-    input->track_name   = g_strdup(p_Tags.title);
-    input->performer    = g_strdup(p_Tags.artist);
-    input->album_name   = g_strdup(p_Tags.album);
-    input->track_number = p_Tags.track;
-    input->year         = p_Tags.year;
-    input->genre        = g_strdup(p_Tags.genre);
-    input->comment      = g_strdup(p_Tags.comment);
-
-    char* title = xmms_get_titlestring (xmms_get_gentitle_format(), input);
-    if(!title)
-        title = g_strdup(input->file_name);
-    else if (!*title)
-        title = g_strdup(input->file_name);
-
-    free(input->file_name);
-    free(input->file_path);
-    free(input->track_name);
-    free(input->performer);
-    free(input->album_name);
-    free(input->genre);
-    free(input->comment);
-    free(input->date);
-    g_free(input);
-    return title;
-}
-
-static void* endThread(char* p_FileName, FILE* p_FileHandle, bool release)
-{
-    free(p_FileName);
+static void* endThread(gchar* p_FileName, VFSFile * p_FileHandle, bool release)
+{
     if(release)
         lockRelease();
@@ -691,186 +742,176 @@
     {
         perror(mpcDecoder.isError);
-        free(mpcDecoder.isError);
+        g_free(mpcDecoder.isError);
         mpcDecoder.isError = NULL;
     }
-    setAlive(false);
+    mpcDecoder.isAlive = false;
     if(p_FileHandle)
-        fclose(p_FileHandle);
+        aud_vfs_fclose(p_FileHandle);
     if(track.display)
     {
-        free(track.display);
+        g_free(track.display);
         track.display = NULL;
     }
-    pthread_exit(NULL);
     return 0;
 }
 
-static void* decodeStream(void* data)
+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();
-	const char* filename = static_cast<const char*> (data);
-	mpc_reader reader;
-	if (mpc_reader_init_stdio(&reader, filename) != MPC_STATUS_OK) {
+    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, 0, true);
+        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_demux * demux = 0;
-	demux = mpc_demux_init(&reader);
-
-	if ( demux == 0 ) {
-		mpcDecoder.isError = g_strdup_printf("[xmms-musepack] decodeStream is unable to initialize decoder on %s", filename);
-		mpc_reader_exit_stdio(&reader);
-		return endThread(filename, 0, true);
-	}
-
-	mpc_streaminfo info;
+    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;
+
+    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);
 
-    MpcPlugin.set_info(track.display, track.length, track.bitrate, track.sampleFreq, track.channels);
-
-    setReplaygain(demux);
+    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 (!MpcPlugin.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");
-		mpc_reader_exit_stdio(&reader);
-        return endThread(filename, 0, true);
-    }
-    else
-    {
-        mpcDecoder.isOutput = true;
-    }
-
+    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();
 
-	int counter = 2 * track.sampleFreq / 3;
+	data->set_pb_ready(data);
+	data->playing = TRUE;
+
+    gint counter = 2 * track.sampleFreq / 3;
 	int status = 0;
-    while (isAlive())
-    {
-        if (getOffset() != -1)
+    while (mpcDecoder.isAlive)
+    {
+        lockAcquire();
+
+		if (mpcDecoder.offset != -1)
         {
-			mpc_demux_seek_second(demux, mpcDecoder.offset);
-            setOffset(-1);
-			status = 0;
+			mpc_demux_seek_sample(demux, mpcDecoder.offset * track.sampleFreq / 1000);
+			data->output->flush(mpcDecoder.offset);
+            mpcDecoder.offset = -1;
         }
 
-        lockAcquire();
-        short iPlaying = MpcPlugin.output->buffer_playing()? 1 : 0;
-        int iFree = MpcPlugin.output->buffer_free();
-        if (!mpcDecoder.isPause &&  iFree >= ((1152 * 4) << iPlaying) && status != -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(sampleBuffer, xmmsBuffer, *demux);
-			lockRelease();
-
-			if(pluginConfig.dynamicBitrate) {
-				counter -= status;
-				if(counter < 0) {
-					MpcPlugin.set_info(track.display, track.length, track.bitrate, track.sampleFreq, track.channels);
-					counter = 2 * track.sampleFreq / 3;
-				}
-			}
+            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();
+            lockRelease();
 			if (mpcDecoder.isPause == FALSE && status == -1 &&
-						 MpcPlugin.output->buffer_playing() == FALSE)
+						 data->output->buffer_playing() == FALSE)
 				break;
-            xmms_usleep(100000);
-		}
-	}
+            g_usleep(60000);
+        }
+    }
 	mpc_demux_exit(demux);
-	mpc_reader_exit_stdio(&reader);
-    return endThread(filename, 0, false);
-}
-
-static int processBuffer(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);
-    }
-
-    if (pluginConfig.isEq)
-    {
-		iir(xmmsBuffer, 4 * info.samples);
-    }
-
-	MpcPlugin.add_vis_pcm(MpcPlugin.output->written_time(), FMT_S16_LE, track.channels, info.samples * 2 * track.channels, xmmsBuffer);
-	MpcPlugin.output->write_audio(xmmsBuffer, info.samples * 2 * track.channels);
-	return info.samples;
-}
-
-static void setReplaygain(mpc_demux * d)
-{
-	mpc_set_replay_level(d, MPC_OLD_GAIN_REF, pluginConfig.replaygain,
-						 !pluginConfig.albumGain, pluginConfig.clipPrevention);
-}
-
-inline static void lockAcquire()
-{
-    pthread_mutex_lock(&threadMutex);
-}
-
-inline static void lockRelease()
-{
-    pthread_mutex_unlock(&threadMutex);
-}
-
-inline static bool isAlive()
-{
-    lockAcquire();
-    bool isAlive = mpcDecoder.isAlive;
-    lockRelease();
-    return isAlive;
-}
-
-inline static bool isPause()
-{
-    lockAcquire();
-    bool isPause = mpcDecoder.isPause;
-    lockRelease();
-    return isPause;
-}
-
-inline static void setAlive(bool isAlive)
-{
-    lockAcquire();
-    mpcDecoder.isAlive = isAlive;
-    lockRelease();
-}
-
-inline static double getOffset()
-{
-    lockAcquire();
-    double offset = mpcDecoder.offset;
-    lockRelease();
-    return offset;
-}
-
-inline static void setOffset(double offset)
-{
-    lockAcquire();
-    mpcDecoder.offset = offset;
-    lockRelease();
-}
+    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);
