changeset 1521:fc246407b2ad

Automated merge with ssh://hg.atheme.org//hg/audacious-plugins
author William Pitcock <nenolod@atheme-project.org>
date Thu, 23 Aug 2007 20:32:48 -0500
parents 2ed7413c199a (current diff) 9e7980b7abad (diff)
children 88f5ba93f3dd
files src/wavpack/libwavpack.cxx
diffstat 24 files changed, 363 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/src/aac/src/libmp4.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/aac/src/libmp4.c	Thu Aug 23 20:32:48 2007 -0500
@@ -389,6 +389,7 @@
         faacDecClose(decoder);
 
         msDuration = ((float)numSamples * (float)(framesize - 1.0)/(float)samplerate) * 1000;
+        tuple_associate_int(ti, "length", msDuration);
 
         mp4ff_meta_get_title(mp4file, &tmpval);
         if (tmpval)
@@ -400,7 +401,7 @@
         mp4ff_meta_get_album(mp4file, &tmpval);
         if (tmpval)
         {
-            tuple_associate_string(ti, "title", tmpval);
+            tuple_associate_string(ti, "album", tmpval);
             free(tmpval);
         }
 
@@ -460,7 +461,7 @@
     gchar *title;
     Tuple *tuple = mp4_get_song_tuple(filename);
 
-    title = tuple_formatter_process_string(tuple, get_gentitle_format());
+    title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 
     tuple_free(tuple);
 
--- a/src/alac/plugin.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/alac/plugin.c	Thu Aug 23 20:32:48 2007 -0500
@@ -336,7 +336,7 @@
 
     /* Get the titlestring ready. */
     ti = build_tuple_from_demux(&demux_res, (char *) args);
-    title = tuple_formatter_process_string(ti, get_gentitle_format());
+    title = tuple_formatter_make_title_string(ti, get_gentitle_format());
 
     /* initialise the sound converter */
     demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels);
--- a/src/cdaudio-ng/cdaudio-ng.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/cdaudio-ng/cdaudio-ng.c	Thu Aug 23 20:32:48 2007 -0500
@@ -1,20 +1,20 @@
-/*
- * Audacious CD Digital Audio plugin
- *
- * Copyright (c) 2007 Calin Crisan <ccrisan@gmail.com>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses>.
- */
+/*
+ * Audacious CD Digital Audio plugin
+ *
+ * Copyright (c) 2007 Calin Crisan <ccrisan@gmail.com>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses>.
+ */
 
 
 #include <string.h>
@@ -522,7 +522,7 @@
 	is_paused = FALSE;
 
 	tuple = create_tuple_from_trackinfo(pinputplayback->filename);
-	title = tuple_formatter_process_string(tuple, get_gentitle_format());
+	title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 
 	inputplugin.set_info(title, calculate_track_length(trackinfo[trackno].startlsn, trackinfo[trackno].endlsn), 1411200, 44100, 2);
 	free(title); title = NULL;
--- a/src/cdaudio-ng/cdaudio-ng.h	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/cdaudio-ng/cdaudio-ng.h	Thu Aug 23 20:32:48 2007 -0500
@@ -1,20 +1,20 @@
-/*
- * Audacious CD Digital Audio plugin
- *
- * Copyright (c) 2007 Calin Crisan <ccrisan@gmail.com>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theio
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses>.
- */
+/*
+ * Audacious CD Digital Audio plugin
+ *
+ * Copyright (c) 2007 Calin Crisan <ccrisan@gmail.com>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses>.
+ */
 
 
 #ifndef CDAUDIO_NG_H
--- a/src/console/Audacious_Driver.cxx	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/console/Audacious_Driver.cxx	Thu Aug 23 20:32:48 2007 -0500
@@ -240,7 +240,7 @@
 
 static char* format_and_free_ti( Tuple* ti, int* length )
 {
-	char* result = tuple_formatter_process_string(ti, get_gentitle_format());
+	char* result = tuple_formatter_make_title_string(ti, get_gentitle_format());
 	if ( result )
 		*length = tuple_get_int(ti, "length");
 	tuple_free((void *) ti);
--- a/src/cue/cuesheet.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/cue/cuesheet.c	Thu Aug 23 20:32:48 2007 -0500
@@ -325,7 +325,7 @@
 
 	g_return_if_fail(tuple != NULL);
 
-	*title = tuple_formatter_process_string(tuple, get_gentitle_format());
+	*title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 	*length = tuple_get_int(tuple, "length");
 
 	tuple_free(tuple);
--- a/src/filewriter/filewriter.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/filewriter/filewriter.c	Thu Aug 23 20:32:48 2007 -0500
@@ -215,7 +215,7 @@
 
     if (filenamefromtags)
     {
-        gchar *utf8 = tuple_formatter_process_string(tuple, get_gentitle_format());
+        gchar *utf8 = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 
         g_strchomp(utf8); //chop trailing ^J --yaz
 
--- a/src/flacng/tools.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/flacng/tools.c	Thu Aug 23 20:32:48 2007 -0500
@@ -284,7 +284,7 @@
 
     input = get_tuple(filename, info);
 
-    title = tuple_formatter_process_string(input, get_gentitle_format());
+    title = tuple_formatter_make_title_string(input, get_gentitle_format());
 
     tuple_free(input);
 
--- a/src/mtp_up/Makefile	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/mtp_up/Makefile	Thu Aug 23 20:32:48 2007 -0500
@@ -8,7 +8,7 @@
 LIBDIR = $(plugindir)/$(GENERAL_PLUGIN_DIR)
 
 LIBADD += $(MTP_LIBS) $(GTK_LIBS) $(GLIB_LIBS) $(PANGO_LIBS) 
-SOURCES = mtp.c
+SOURCES = mtp.c filetype.c
 
 CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) $(BEEP_DEFINES) -I../../intl -I../..
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtp_up/filetype.c	Thu Aug 23 20:32:48 2007 -0500
@@ -0,0 +1,85 @@
+/*This code was copied shamelessly from libMTP's examples*/
+#include "string.h"
+#include "filetype.h"
+
+/* Find the file type based on extension */
+LIBMTP_filetype_t
+find_filetype (const char * filename)
+{
+  char *ptype;
+  ptype = rindex(filename,'.')+1;
+  LIBMTP_filetype_t filetype;
+  /* This need to be kept constantly updated as new file types arrive. */
+  if (!strcasecmp (ptype, "wav")) {
+    filetype = LIBMTP_FILETYPE_WAV;
+  } else if (!strcasecmp (ptype, "mp3")) {
+    filetype = LIBMTP_FILETYPE_MP3;
+  } else if (!strcasecmp (ptype, "wma")) {
+    filetype = LIBMTP_FILETYPE_WMA;
+  } else if (!strcasecmp (ptype, "ogg")) {
+    filetype = LIBMTP_FILETYPE_OGG;
+  } else if (!strcasecmp (ptype, "mp4")) {
+    filetype = LIBMTP_FILETYPE_MP4;
+  } else if (!strcasecmp (ptype, "wmv")) {
+    filetype = LIBMTP_FILETYPE_WMV;
+  } else if (!strcasecmp (ptype, "avi")) {
+    filetype = LIBMTP_FILETYPE_AVI;
+  } else if (!strcasecmp (ptype, "mpeg") || !strcasecmp (ptype, "mpg")) {
+    filetype = LIBMTP_FILETYPE_MPEG;
+  } else if (!strcasecmp (ptype, "asf")) {
+    filetype = LIBMTP_FILETYPE_ASF;
+  } else if (!strcasecmp (ptype, "qt") || !strcasecmp (ptype, "mov")) {
+    filetype = LIBMTP_FILETYPE_QT;
+  } else if (!strcasecmp (ptype, "wma")) {
+    filetype = LIBMTP_FILETYPE_WMA;
+  } else if (!strcasecmp (ptype, "jpg") || !strcasecmp (ptype, "jpeg")) {
+    filetype = LIBMTP_FILETYPE_JPEG;
+  } else if (!strcasecmp (ptype, "jfif")) {
+    filetype = LIBMTP_FILETYPE_JFIF;
+  } else if (!strcasecmp (ptype, "tif") || !strcasecmp (ptype, "tiff")) {
+    filetype = LIBMTP_FILETYPE_TIFF;
+  } else if (!strcasecmp (ptype, "bmp")) {
+    filetype = LIBMTP_FILETYPE_BMP;
+  } else if (!strcasecmp (ptype, "gif")) {
+    filetype = LIBMTP_FILETYPE_GIF;
+  } else if (!strcasecmp (ptype, "pic") || !strcasecmp (ptype, "pict")) {
+    filetype = LIBMTP_FILETYPE_PICT;
+  } else if (!strcasecmp (ptype, "png")) {
+    filetype = LIBMTP_FILETYPE_PNG;
+  } else if (!strcasecmp (ptype, "wmf")) {
+    filetype = LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT;
+  } else if (!strcasecmp (ptype, "ics")) {
+    filetype = LIBMTP_FILETYPE_VCALENDAR2;
+  } else if (!strcasecmp (ptype, "exe") || !strcasecmp (ptype, "com") ||
+	     !strcasecmp (ptype, "bat") || !strcasecmp (ptype, "dll") ||
+	     !strcasecmp (ptype, "sys")) {
+    filetype = LIBMTP_FILETYPE_WINEXEC;
+  } else if (!strcasecmp (ptype, "aac")) {
+    filetype = LIBMTP_FILETYPE_AAC;
+  } else if (!strcasecmp (ptype, "mp2")) {
+    filetype = LIBMTP_FILETYPE_MP2;
+  } else if (!strcasecmp (ptype, "flac")) {
+    filetype = LIBMTP_FILETYPE_FLAC;
+  } else if (!strcasecmp (ptype, "m4a")) {
+    filetype = LIBMTP_FILETYPE_M4A;
+  } else if (!strcasecmp (ptype, "doc")) {
+    filetype = LIBMTP_FILETYPE_DOC;
+  } else if (!strcasecmp (ptype, "xml")) {
+    filetype = LIBMTP_FILETYPE_XML;
+  } else if (!strcasecmp (ptype, "xls")) {
+    filetype = LIBMTP_FILETYPE_XLS;
+  } else if (!strcasecmp (ptype, "ppt")) {
+    filetype = LIBMTP_FILETYPE_PPT;
+  } else if (!strcasecmp (ptype, "mht")) {
+    filetype = LIBMTP_FILETYPE_MHT;
+  } else if (!strcasecmp (ptype, "jp2")) {
+    filetype = LIBMTP_FILETYPE_JP2;
+  } else if (!strcasecmp (ptype, "jpx")) {
+    filetype = LIBMTP_FILETYPE_JPX;
+  } else {
+    /* Tagging as unknown file type */
+    filetype = LIBMTP_FILETYPE_UNKNOWN;
+  }
+  return filetype;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtp_up/filetype.h	Thu Aug 23 20:32:48 2007 -0500
@@ -0,0 +1,5 @@
+#include <libmtp.h>
+#include <glib.h>
+
+LIBMTP_filetype_t find_filetype (const char *);
+
--- a/src/mtp_up/mtp.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/mtp_up/mtp.c	Thu Aug 23 20:32:48 2007 -0500
@@ -17,6 +17,7 @@
  */
 
 #include <glib.h>
+#include <sys/types.h>
 #include <libmtp.h>
 #include <audacious/plugin.h>
 #include <audacious/playlist.h>
@@ -24,13 +25,13 @@
 
 #include <gtk/gtk.h>
 #include <audacious/util.h>
-
+#include "filetype.h"
 #define DEBUG 1
 
-#define DEFAULT_LABEL "Upload to MTP device"
-#define DISABLED_LABEL "MTP upload in progress..."
-
-
+#define ROOT_LABEL "MTP device handler"
+#define UP_DEFAULT_LABEL "Upload selected track(s)"
+#define UP_BUSY_LABEL "Upload in progress..."
+#define FREE_LABEL      "Disconnect the device"
 GMutex * mutex = NULL; 
 gboolean mtp_initialised = FALSE;
 LIBMTP_mtpdevice_t *mtp_device = NULL;
@@ -55,7 +56,7 @@
     mtp_prefs,                              /* configure */
     mtp_cleanup                             /* cleanup */
 };
-GtkWidget *menuitem;
+GtkWidget *mtp_root_menuitem,*mtp_submenu_item_up,*mtp_submenu_item_free,*mtp_submenu;
 
 GeneralPlugin *mtp_gplist[] = { &mtp_gp, NULL };
 DECLARE_PLUGIN(mtp_gp, NULL, NULL, NULL, NULL, NULL, mtp_gplist, NULL, NULL)
@@ -71,17 +72,39 @@
             message);
     gtk_dialog_run (GTK_DIALOG (dialog));
     gtk_widget_show(dialog);
-    gtk_widget_destroy(dialog);
+   /* gtk_widget_destroy(dialog); */
     GDK_THREADS_LEAVE();
 
 }
 
+gboolean free_device(void)
+{
+#if DEBUG
+        if(mtp_initialised)
+                   g_print("\n\n                 !!!CAUTION!!! \n\n"
+                    "Cleaning up MTP upload plugin, please wait!!!...\n"
+                    "This will block until the pending tracks are uploaded,\n"
+                    "then it will gracefully close your device\n\n"
+                    "!!! FORCING SHUTDOWN NOW MAY CAUSE DAMAGE TO YOUR DEVICE !!!\n\n\n"
+                    "Waiting for the MTP mutex to unlock...\n");
+#endif
+        if(!mutex)
+            return TRUE;
+        g_mutex_lock(mutex);
+        if(mtp_device!= NULL)
+        {
+            LIBMTP_Release_Device(mtp_device);
+            mtp_device = NULL;
+            mtp_initialised = FALSE;
+            gtk_widget_hide(mtp_submenu_item_free);
+        }
+        g_mutex_unlock(mutex);
+return TRUE;        
+}
 
 GList * get_upload_list()
 {
     Tuple *tuple;
-    gchar *from_path,*filename;
-    VFSFile*f;
     GList *node=NULL,*up_list=NULL;
     PlaylistEntry *entry;
     Playlist *current_play = playlist_get_active();
@@ -94,31 +117,8 @@
         if (entry->selected)  
         {
             tuple = entry->tuple;
-            from_path = g_strdup_printf("%s/%s", tuple_get_string(tuple, "file-path"), tuple_get_string(tuple, "file-name"));
-            gchar *tmp;
-            tmp = g_strescape(from_path,NULL);
-            filename=g_filename_from_uri(tmp,NULL,NULL);
-
-            if(filename)
-            {
-                f = vfs_fopen(from_path,"r");
-                if(!vfs_is_streaming(f))
-
-
-                    up_list=g_list_prepend(up_list,filename);
-
-                g_free(tmp);
-                vfs_fclose(f);
-
-            }
-            else 
-            {
-                up_list = g_list_prepend(up_list,tmp);
-                g_free(filename);
-            }
-
+            up_list=g_list_prepend(up_list,tuple);        
             entry->selected = FALSE;
-            g_free(from_path);
         }
         node = g_list_next(node);
     }
@@ -126,107 +126,136 @@
     return g_list_reverse(up_list);
 }
 
-gint upload_file(gchar *from_path)
+LIBMTP_track_t *track_metadata(Tuple *from_tuple)
 {
-    int ret;
-    gchar *comp, *filename;
+    LIBMTP_track_t *tr;
+    gchar *from_path,*filename;
+    VFSFile *f;
     uint64_t filesize;
     uint32_t parent_id = 0;
     struct stat sb;
-    LIBMTP_file_t *genfile;
 
-    comp = g_strescape(from_path,NULL);
+    from_path = g_strdup_printf("%s/%s", tuple_get_string(from_tuple, "file-path"), tuple_get_string(from_tuple, "file-name"));
+    gchar *tmp;
+    tmp = g_strescape(from_path,NULL);
+    filename=g_filename_from_uri(tmp,NULL,NULL);
+    /* dealing the stream uploa (invalidating)*/
+    if(filename)
+    {
+        f = vfs_fopen(from_path,"r");
+        if(vfs_is_streaming(f)) 
+        {
+            vfs_fclose(f);
+            return NULL;
+        }
+    }       
+
     if ( stat(from_path, &sb) == -1 )
     {
 #if DEBUG
         g_print("ERROR! encountered while stat()'ing \"%s\"\n",from_path);
 #endif
-        return 1;
+        return NULL;
     }
     filesize = (uint64_t) sb.st_size;
-    filename = g_path_get_basename(from_path);
     parent_id = mtp_device->default_music_folder;
-#if DEBUG 
-    g_print("Parent id : %d\n",parent_id); 
-#endif    
-    genfile = LIBMTP_new_file_t();
-    genfile->filesize = filesize;
-    genfile->filename = strdup(filename);
+
+    /* track metadata*/
+    tr = LIBMTP_new_track_t();
+    tr->title =g_strdup((gchar*) tuple_get_string(from_tuple, "title")); 
+    tr->artist =g_strdup((gchar*) tuple_get_string(from_tuple,"artist"));
+    tr->album = g_strdup((gchar*)tuple_get_string(from_tuple,"album"));
+    tr->filesize = filesize;
+    tr->filename = g_strdup(from_path);
+    tr->duration = (uint32_t)tuple_get_int(from_tuple, "length");
+    tr->filetype = find_filetype (from_path);
+    tr->genre = g_strdup((gchar*)tuple_get_string(from_tuple, "genre"));
+    tr->date = g_strdup_printf("%d",tuple_get_int(from_tuple, "year"));
+
+    g_free(filename);
+    g_free(from_path);
+    g_free(tmp);
+    return tr;
+}
+
+gint upload_file(Tuple *from_tuple)
+{
+    int ret;
+    gchar *comp;
+    uint32_t parent_id = 0;
+    LIBMTP_track_t *gentrack;
+
+    gentrack = track_metadata(from_tuple);
+    if(gentrack == NULL) return 1;
+
+    comp = g_strescape(gentrack->filename,NULL);
+    parent_id = mtp_device->default_music_folder;
+
 #if DEBUG
     g_print("Uploading track '%s'\n",comp);
 #endif
-    ret = LIBMTP_Send_File_From_File(mtp_device, comp , genfile, NULL , NULL, parent_id);
+    ret = LIBMTP_Send_Track_From_File(mtp_device, comp , gentrack, NULL , NULL, parent_id);
+    LIBMTP_destroy_track_t(gentrack);
     if (ret == 0) 
-        g_print("Upload finished!\n");
+        g_print("Track upload finished!\n");
     else
     {
         g_print("An error has occured while uploading '%s'...\nUpload failed!!!",comp);
         mtp_initialised = FALSE;
         return 1;
     }
-    LIBMTP_destroy_file_t(genfile);
-#if DEBUG 
-    g_print("genfile destroyed \n");    
-#endif    
-    g_free(filename);
-    g_free(comp);
-#if DEBUG
-    g_print("Free ok..exiting upload_file \n ");    
-#endif
+
     return 0;
 }
 
 
 gpointer upload(gpointer arg)
 {
-     if(!mutex)
-       {
-       gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))),DEFAULT_LABEL);
-       gtk_widget_set_sensitive(menuitem, TRUE);
-       return NULL;
-       } 
-       g_mutex_lock(mutex); 
+    gtk_widget_hide(mtp_submenu_item_free);
+    if(!mutex)
+    {
+        gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mtp_submenu_item_up))),UP_DEFAULT_LABEL);
+        gtk_widget_set_sensitive(mtp_submenu_item_up, TRUE);
+        return NULL;
+    } 
+    g_mutex_lock(mutex); 
     if(!mtp_device)
-    {
-        gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))),DEFAULT_LABEL);
-        gtk_widget_set_sensitive(menuitem, TRUE);
-                g_mutex_unlock(mutex); 
+    { 
+        gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mtp_submenu_item_up))),UP_DEFAULT_LABEL);
+        gtk_widget_set_sensitive(mtp_submenu_item_up, TRUE);
+        g_mutex_unlock(mutex); 
         return NULL;
     }
 
-    gchar* from_path;
-
+    Tuple* tuple;
     GList *up_list=NULL,*node;
     node=up_list=get_upload_list();
     gint up_err=0;
     while(node)
     {
-        from_path=(gchar*)(node->data);
-        up_err = upload_file(from_path);
+        tuple=(Tuple*)(node->data);
+        up_err = upload_file(tuple);
         if(up_err )
-         {
-             show_dialog("An error has occured while uploading...\nUpload failed!");
-             break;
-         }
-         if(exiting)
-         {
-             /*show_dialog("Shutting down MTP while uploading.\nPending uploads were cancelled");*/
-             break;
-         }
+        {
+            show_dialog("An error has occured while uploading...\nUpload failed!");
+            break;
+        }
+        if(exiting)
+        {
+            /*show_dialog("Shutting down MTP while uploading.\nPending uploads were cancelled");*/
+            break;
+        }
 
         node = g_list_next(node);
     }
     g_list_free(up_list);
+    gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mtp_submenu_item_up))),UP_DEFAULT_LABEL);
+    gtk_widget_set_sensitive(mtp_submenu_item_up, TRUE);
+    g_mutex_unlock(mutex); 
 #if DEBUG
-    g_print("up_list free ok, seting menuitem ...\n");
+    g_print("MTP upload process finished\n");
 #endif    
-
-    gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))),DEFAULT_LABEL);
-    gtk_widget_set_sensitive(menuitem, TRUE);
-      g_mutex_unlock(mutex); 
-#if DEBUG
-    g_print("upload thread killed exiting upload function\n");
-#endif    
+    gtk_widget_show(mtp_submenu_item_free);
     g_thread_exit(NULL);
     return NULL;
 }
@@ -242,10 +271,10 @@
     /*about stub*/
 }
 
-void mtp_press()
+gboolean mtp_press()
 {
     if(!mutex) 
-        return;
+        return TRUE;
     g_mutex_lock(mutex);
     if(!mtp_initialised)
     {
@@ -255,6 +284,8 @@
         LIBMTP_Init();
         mtp_device = LIBMTP_Get_First_Device();
         mtp_initialised = TRUE;
+        gtk_widget_show(mtp_submenu_item_free);
+
     }
     g_mutex_unlock(mutex);
     if(mtp_device == NULL) 
@@ -262,24 +293,41 @@
 #if DEBUG
         g_print("No MTP devices have been found !!!");
 #endif  
-        show_dialog("No MTP devices have been found !!!");
+       /* show_dialog("No MTP devices have been found !!!"); */
         mtp_initialised = FALSE;
-        return;
+        return TRUE;
 
     }
-    gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))),DISABLED_LABEL);
-    gtk_widget_set_sensitive(menuitem, FALSE);
+    gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mtp_submenu_item_up))),UP_BUSY_LABEL);
+    gtk_widget_set_sensitive(mtp_submenu_item_up, FALSE);
     g_thread_create(upload,NULL,FALSE,NULL); 
-    return;
+    return TRUE;
 
 }
 
 void mtp_init(void)
 {
-    menuitem=gtk_menu_item_new_with_label(DEFAULT_LABEL);
-    gtk_widget_show (menuitem);
-    audacious_menu_plugin_item_add(AUDACIOUS_MENU_PLAYLIST_RCLICK, menuitem);
-    g_signal_connect (G_OBJECT (menuitem), "button_press_event",G_CALLBACK (mtp_press), NULL);  
+    mtp_root_menuitem=gtk_menu_item_new_with_label(ROOT_LABEL);
+    mtp_submenu=gtk_menu_new();
+
+    mtp_submenu_item_up=gtk_menu_item_new_with_label(UP_DEFAULT_LABEL);
+    mtp_submenu_item_free=gtk_menu_item_new_with_label(FREE_LABEL);
+
+
+    gtk_menu_shell_append (GTK_MENU_SHELL (mtp_submenu), mtp_submenu_item_up);
+    gtk_widget_show (mtp_submenu_item_up);
+
+    gtk_menu_shell_append (GTK_MENU_SHELL (mtp_submenu), mtp_submenu_item_free);
+  
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM(mtp_root_menuitem),mtp_submenu);
+    gtk_widget_show (mtp_submenu);
+    gtk_widget_show (mtp_root_menuitem);
+
+
+    audacious_menu_plugin_item_add(AUDACIOUS_MENU_PLAYLIST_RCLICK, mtp_root_menuitem);
+    g_signal_connect (G_OBJECT (mtp_submenu_item_up), "button_press_event",G_CALLBACK (mtp_press), NULL);  
+    g_signal_connect (G_OBJECT (mtp_submenu_item_free), "button_press_event",G_CALLBACK (free_device), NULL);  
+    
     mutex = g_mutex_new();
     plugin_active = TRUE;
     exiting=FALSE;
@@ -292,15 +340,15 @@
 
 #if DEBUG
         if(mtp_initialised)
-           {
-               g_print("\n\n                 !!!CAUTION!!! \n\n"
+        {
+            g_print("\n\n                 !!!CAUTION!!! \n\n"
                     "Cleaning up MTP upload plugin, please wait!!!...\n"
                     "This will block until the pending tracks are uploaded,\n"
                     "then it will gracefully close your device\n\n"
                     "!!! FORCING SHUTDOWN NOW MAY CAUSE DAMAGE TO YOUR DEVICE !!!\n\n\n"
                     "Waiting for the MTP mutex to unlock...\n");
-               exiting=TRUE;
-           }
+            exiting=TRUE;
+        }
 #endif
         if(mutex)
             g_mutex_lock(mutex);
@@ -314,8 +362,16 @@
         if(mtp_initialised)
             g_print("The MTP mutex has been unlocked\n");
 #endif
-        audacious_menu_plugin_item_remove(AUDACIOUS_MENU_PLAYLIST_RCLICK, menuitem);
-        gtk_widget_destroy(menuitem);
+        audacious_menu_plugin_item_remove(AUDACIOUS_MENU_PLAYLIST_RCLICK, mtp_root_menuitem);
+        gtk_widget_destroy(mtp_submenu_item_up);
+
+        gtk_widget_destroy(mtp_submenu_item_up);
+        gtk_widget_destroy(mtp_submenu_item_free);
+
+        gtk_widget_destroy(mtp_submenu);
+
+        gtk_widget_destroy(mtp_root_menuitem);
+        
         g_mutex_free (mutex);
         mutex = NULL;
         plugin_active = FALSE;
--- a/src/musepack/libmpc.cxx	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/musepack/libmpc.cxx	Thu Aug 23 20:32:48 2007 -0500
@@ -742,10 +742,7 @@
 {
     Tuple* tuple = mpcGetSongTuple(p_Filename);
 
-    char* title = tuple_formatter_process_string(tuple, get_gentitle_format());
-
-    if (!*title)
-        title = g_strdup(tuple_get_string(tuple, "file-name"));
+    char* title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 
     tuple_free((void *) tuple);
     return title;
--- a/src/sexypsf/plugin.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/sexypsf/plugin.c	Thu Aug 23 20:32:48 2007 -0500
@@ -251,7 +251,7 @@
     Tuple *tuple = get_tuple_psf(fn);
 
     if (tuple != NULL) {
-        title = tuple_formatter_process_string(tuple, get_gentitle_format());
+        title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
         tuple_free(tuple);
     }
     else
--- a/src/sid/xmms-sid.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/sid/xmms-sid.c	Thu Aug 23 20:32:48 2007 -0500
@@ -290,6 +290,14 @@
 }
 
 
+static gboolean xs_schedule_subctrl_update( gpointer unused )
+{
+	if (xs_status.isPlaying == TRUE )
+		xs_subctrl_update();
+	return FALSE;
+}
+
+
 /*
  * Main playing thread loop
  */
@@ -387,9 +395,7 @@
 
 		XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
 
-		GDK_THREADS_ENTER();
-		xs_subctrl_update();
-		GDK_THREADS_LEAVE();
+		g_idle_add_full( G_PRIORITY_HIGH_IDLE , xs_schedule_subctrl_update , NULL , NULL );
 
 		/* Check minimum playtime */
 		songLength = myTune->subTunes[myStatus.currSong-1].tuneLength;
--- a/src/sid/xs_title.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/sid/xs_title.c	Thu Aug 23 20:32:48 2007 -0500
@@ -141,7 +141,7 @@
    if (!xs_cfg.titleOverride) {
 		t_xs_tuple *pTuple = xs_get_titletuple(
 			tmpFilename, tmpFilePath, tmpFileExt, p, subTune);
-		pcResult = tuple_formatter_process_string(pTuple, get_gentitle_format());
+		pcResult = tuple_formatter_make_title_string(pTuple, get_gentitle_format());
 		tuple_free(pTuple);
 	} else
 #elif defined(HAVE_XMMSEXTRA)
--- a/src/timidity/src/xmms-timidity.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/timidity/src/xmms-timidity.c	Thu Aug 23 20:32:48 2007 -0500
@@ -310,7 +310,7 @@
 
 	input = tuple_new_from_filename(filename);
 
-	title = tuple_formatter_process_string(input, get_gentitle_format());
+	title = tuple_formatter_make_title_string(input, get_gentitle_format());
 	if (title == NULL || *title == '\0')
 		title = g_strdup(tuple_get_string(input, "file-name"));
 
--- a/src/tta/libtta.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/tta/libtta.c	Thu Aug 23 20:32:48 2007 -0500
@@ -72,7 +72,7 @@
 static void file_info (char *filename);
 static void about ();
 static Tuple *get_song_tuple(char *filename);
-static gchar *extname(const char *filename);
+//static gchar *extname(const char *filename);
 
 static GThread *decode_thread = NULL;
 static char sample_buffer[PCM_BUFFER_LENGTH * MAX_BSIZE * MAX_NCH];
@@ -177,7 +177,7 @@
 static gchar *
 get_song_title(Tuple *tuple)
 {
-	return tuple_formatter_process_string(tuple, get_gentitle_format());
+	return tuple_formatter_make_title_string(tuple, get_gentitle_format());
 }
 
 static void
@@ -570,7 +570,6 @@
 	Tuple *tuple = NULL;
 	tta_info *ttainfo;
 	VFSFile *file;
-	gchar *realfn = NULL;
 
 	ttainfo = g_malloc0(sizeof(tta_info));
 
@@ -610,6 +609,7 @@
 	return tuple;
 }
 
+#if 0
 static gchar *
 extname(const char *filename)
 {
@@ -620,6 +620,7 @@
 
 	return ext;
 }
+#endif
 
 /* return length in letters */
 size_t tta_ucs4len(id3_ucs4_t *ucs)
--- a/src/vtx/vtx.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/vtx/vtx.c	Thu Aug 23 20:32:48 2007 -0500
@@ -234,7 +234,7 @@
       seek_to = -1;
 
       ti = vtx_get_song_tuple_from_vtx(playback->filename, &vtx);
-      buf = tuple_formatter_process_string(ti, get_gentitle_format());
+      buf = tuple_formatter_make_title_string(ti, get_gentitle_format());
 
       vtx_ip.set_info (buf, vtx.hdr.regdata_size / 14 * 1000 / 50,
  	  	       14 * 50 * 8, freq, bits / 8);
--- a/src/wav/wav-sndfile.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/wav/wav-sndfile.c	Thu Aug 23 20:32:48 2007 -0500
@@ -120,11 +120,22 @@
 {
 	SNDFILE	*tmp_sndfile;
 	SF_INFO tmp_sfinfo;
+	unsigned int lossy = 0;
 	gchar *realfn = NULL, *codec = NULL, *format, *subformat = NULL;
 	GString *codec_gs = NULL;
 
 	realfn = g_filename_from_uri(filename, NULL, NULL);
 	tmp_sndfile = sf_open (realfn ? realfn : filename, SFM_READ, &tmp_sfinfo);
+	if ( sf_get_string(tmp_sndfile, SF_STR_TITLE) == NULL)
+		tuple_associate_string(ti, "title", g_path_get_basename(realfn ? realfn : filename));
+	else
+		tuple_associate_string(ti, "title", sf_get_string(tmp_sndfile, SF_STR_TITLE));
+
+	tuple_associate_string(ti, "artist", sf_get_string(tmp_sndfile, SF_STR_ARTIST));
+	tuple_associate_string(ti, "comment", sf_get_string(tmp_sndfile, SF_STR_COMMENT));
+	tuple_associate_string(ti, "date", sf_get_string(tmp_sndfile, SF_STR_DATE));
+	tuple_associate_string(ti, "software", sf_get_string(tmp_sndfile, SF_STR_SOFTWARE));
+
 	g_free(realfn); realfn = NULL;
 
 	if (!tmp_sndfile)
@@ -227,42 +238,55 @@
 			break;
 		case SF_FORMAT_ULAW:
 			subformat = "U-Law";
+			lossy = 1;
 			break;
 		case SF_FORMAT_ALAW:
 			subformat = "A-Law";
+			lossy = 1;
 			break;
 		case SF_FORMAT_IMA_ADPCM:
 			subformat = "IMA ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_MS_ADPCM:
 			subformat = "MS ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_GSM610:
 			subformat = "GSM 6.10";
+			lossy = 1;
 			break;
 		case SF_FORMAT_VOX_ADPCM:
 			subformat = "Oki Dialogic ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_G721_32:
 			subformat = "32kbs G721 ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_G723_24:
 			subformat = "24kbs G723 ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_G723_40:
 			subformat = "40kbs G723 ADPCM";
+			lossy = 1;
 			break;
 		case SF_FORMAT_DWVW_12:
 			subformat = "12 bit Delta Width Variable Word";
+			lossy = 1;
 			break;
 		case SF_FORMAT_DWVW_16:
 			subformat = "16 bit Delta Width Variable Word";
+			lossy = 1;
 			break;
 		case SF_FORMAT_DWVW_24:
 			subformat = "24 bit Delta Width Variable Word";
+			lossy = 1;
 			break;
 		case SF_FORMAT_DWVW_N:
 			subformat = "N bit Delta Width Variable Word";
+			lossy = 1;
 			break;
 		case SF_FORMAT_DPCM_8:
 			subformat = "8 bit differential PCM";
@@ -278,18 +302,29 @@
 		g_string_append_printf(codec_gs, "%s", format);
 	codec = g_strdup(codec_gs->str);
 	g_string_free(codec_gs, TRUE);
+	tuple_associate_string(ti, "codec", codec);
 
-	tuple_associate_string(ti, "codec", codec);
+	if (lossy != 0)
+		tuple_associate_string(ti, "quality", "lossy");
+	else
+		tuple_associate_string(ti, "quality", "lossless");
 }
 
 static gchar *get_title(char *filename)
 {
+	Tuple *tuple;
 	gchar *title;
-	gchar *realfn = NULL;
 
-	realfn = g_filename_from_uri(filename, NULL, NULL);
-	title = g_path_get_basename(realfn ? realfn : filename);
-	g_free(realfn); realfn = NULL;
+	tuple = tuple_new_from_filename(filename);
+	fill_song_tuple(filename, tuple);
+	title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
+	if (*title == '\0')
+	{
+		g_free(title);
+		title = g_strdup(tuple_get_string(tuple, "file-name"));
+	}
+
+	tuple_free(tuple);
 	return title;
 }
 
@@ -443,7 +478,8 @@
 	playback->playing = TRUE;
 
 	decode_thread = g_thread_self();
-        play_loop(playback);
+	playback->set_pb_ready(playback);
+	play_loop(playback);
 }
 
 static void
@@ -485,8 +521,8 @@
 static void
 file_seek (InputPlayback *playback, int time)
 {
-    gulong millisecond = time * 1000;
-    file_mseek(playback, millisecond);
+	gulong millisecond = time * 1000;
+	file_mseek(playback, millisecond);
 }
 
 static void
--- a/src/wav/wav.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/wav/wav.c	Thu Aug 23 20:32:48 2007 -0500
@@ -215,7 +215,7 @@
     tuple_associate_string(tuple, "codec", "RIFF/WAV Audio (ADPCM)");
     tuple_associate_string(tuple, "quality", "lossless");
 
-    title = tuple_formatter_process_string(tuple, get_gentitle_format());
+    title = tuple_formatter_make_title_string(tuple, get_gentitle_format());
     if (*title == '\0')
     {
         g_free(title);
--- a/src/wavpack/libwavpack.cxx	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/wavpack/libwavpack.cxx	Thu Aug 23 20:32:48 2007 -0500
@@ -422,7 +422,7 @@
 
     ti = tuple_from_WavpackContext(fn, ctx);
 
-    displaytitle = tuple_formatter_process_string(ti, cfg.gentitle_format);
+    displaytitle = tuple_formatter_make_title_string(ti, cfg.gentitle_format);
     if (!displaytitle || *displaytitle == '\0')
         displaytitle = g_strdup(fn);
 
--- a/src/wma/wma.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/wma/wma.c	Thu Aug 23 20:32:48 2007 -0500
@@ -303,7 +303,7 @@
     if (in->duration)
         tuple_associate_int(ti, "length", in->duration / 1000);
     
-    ret = tuple_formatter_process_string(ti, get_gentitle_format());
+    ret = tuple_formatter_make_title_string(ti, get_gentitle_format());
 
     return ret;
 }
@@ -324,7 +324,7 @@
         return;
 
     (*len_real) = tuple_get_int(tuple, "length");
-    (*title_real) = tuple_formatter_process_string(tuple, get_gentitle_format());
+    (*title_real) = tuple_formatter_make_title_string(tuple, get_gentitle_format());
 }
 
 static void wma_playbuff(InputPlayback *playback, int out_size)
--- a/src/xspf/xspf.c	Thu Aug 23 20:32:41 2007 -0500
+++ b/src/xspf/xspf.c	Thu Aug 23 20:32:48 2007 -0500
@@ -280,7 +280,7 @@
 #ifdef DEBUG
     printf("playlist_load_xspf: filename = %s\n", filename);
 #endif
-    doc = xmlParseFile(filename);
+    doc = xmlRecoverFile(filename);
     if(doc == NULL)
         return;