changeset 2251:708f89aaee06

Automated merge with ssh://hg.atheme.org//hg/audacious-plugins
author Eugene Paskevich <eugene@raptor.kiev.ua>
date Wed, 19 Dec 2007 12:23:30 +0200
parents 94dae4df1e10 (current diff) a95b6a94682d (diff)
children 27fe97a846a4
files src/projectm-1.0/video_init.cxx src/projectm-1.0/video_init.h
diffstat 20 files changed, 417 insertions(+), 546 deletions(-) [+]
line wrap: on
line diff
--- a/src/adplug/adplug-xmms.cc	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/adplug/adplug-xmms.cc	Wed Dec 19 12:23:30 2007 +0200
@@ -139,6 +139,7 @@
   return GTK_WIDGET (label);
 }
 
+#if 0
 static void
 MessageBox (const char *title, const char *text, const char *button)
 {
@@ -158,6 +159,7 @@
   free (tmptxt);
   free (tmpbutton);
 }
+#endif
 
 /***** Dialog boxes *****/
 
--- a/src/adplug/core/dmo.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/adplug/core/dmo.cxx	Wed Dec 19 12:23:30 2007 +0200
@@ -349,8 +349,10 @@
       if (opos + cx >= oend)
         return -1;
 
-      for (int i = 0; i < cx; i++)
-        *opos++ = *(opos - ax);
+      for (int i = 0; i < cx; i++) {
+        *opos = *(opos - ax);
+        opos++;
+      }
 
       continue;
     }
@@ -370,8 +372,10 @@
       if (opos + bx + cx >= oend)
         return -1;
 
-      for (i = 0; i < cx; i++)
-        *opos++ = *(opos - ax);
+      for (i = 0; i < cx; i++) {
+        *opos = *(opos - ax);
+        opos++;
+      }
 
       for (i = 0; i < bx; i++)
         *opos++ = *ipos++;
@@ -395,8 +399,10 @@
       if (opos + ax + cx >= oend)
         return -1;
 
-      for (i = 0; i < cx; i++)
-        *opos++ = *(opos - bx);
+      for (i = 0; i < cx; i++) {
+        *opos = *(opos - bx);
+        opos++;
+      }
 
       for (i = 0; i < ax; i++)
         *opos++ = *ipos++;
--- a/src/adplug/core/jbm.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/adplug/core/jbm.cxx	Wed Dec 19 12:23:30 2007 +0200
@@ -75,7 +75,7 @@
   // Allocate memory buffer m[] and read entire file into it
 
   m = new unsigned char[filelen];
-  if (f->readString((char *)m, filelen) != filelen) goto loaderr;
+  if (f->readString((char *)m, filelen) != (unsigned int)filelen) goto loaderr;
 
   fp.close(f);
 
--- a/src/console/Blip_Buffer.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Blip_Buffer.cxx	Wed Dec 19 12:23:30 2007 +0200
@@ -27,7 +27,7 @@
 
 Blip_Buffer::Blip_Buffer()
 {
-	factor_       = LONG_MAX;
+	factor_       = UINT_MAX;
 	offset_       = 0;
 	buffer_       = 0;
 	buffer_size_  = 0;
--- a/src/console/Blip_Buffer.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Blip_Buffer.h	Wed Dec 19 12:23:30 2007 +0200
@@ -8,7 +8,7 @@
 	#include <limits.h>
 	#if INT_MAX >= 0x7FFFFFFF
 		typedef int blip_long;
-		typedef unsigned blip_ulong;
+		typedef unsigned int blip_ulong;
 	#else
 		typedef long blip_long;
 		typedef unsigned long blip_ulong;
--- a/src/console/Hes_Cpu.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Hes_Cpu.h	Wed Dec 19 12:23:30 2007 +0200
@@ -8,7 +8,7 @@
 
 typedef blargg_long hes_time_t; // clock cycle count
 typedef unsigned hes_addr_t; // 16-bit address
-enum { future_hes_time = LONG_MAX / 2 + 1 };
+enum { future_hes_time = INT_MAX / 2 + 1 };
 
 class Hes_Cpu {
 public:
--- a/src/console/Music_Emu.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Music_Emu.cxx	Wed Dec 19 12:23:30 2007 +0200
@@ -33,7 +33,7 @@
 	emu_time         = 0;
 	emu_track_ended_ = true;
 	track_ended_     = true;
-	fade_start       = LONG_MAX / 2 + 1;
+	fade_start       = INT_MAX / 2 + 1;
 	fade_step        = 1;
 	silence_time     = 0;
 	silence_count    = 0;
--- a/src/console/Nes_Apu.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Nes_Apu.h	Wed Dec 19 12:23:30 2007 +0200
@@ -78,7 +78,7 @@
 	// Get time that APU-generated IRQ will occur if no further register reads
 	// or writes occur. If IRQ is already pending, returns irq_waiting. If no
 	// IRQ will occur, returns no_irq.
-	enum { no_irq = LONG_MAX / 2 + 1 };
+	enum { no_irq = INT_MAX / 2 + 1 };
 	enum { irq_waiting = 0 };
 	nes_time_t earliest_irq( nes_time_t ) const;
 	
--- a/src/console/Nes_Cpu.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Nes_Cpu.h	Wed Dec 19 12:23:30 2007 +0200
@@ -8,7 +8,7 @@
 
 typedef blargg_long nes_time_t; // clock cycle count
 typedef unsigned nes_addr_t; // 16-bit address
-enum { future_nes_time = LONG_MAX / 2 + 1 };
+enum { future_nes_time = INT_MAX / 2 + 1 };
 
 class Nes_Cpu {
 public:
--- a/src/console/Sap_Cpu.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/console/Sap_Cpu.h	Wed Dec 19 12:23:30 2007 +0200
@@ -8,7 +8,7 @@
 
 typedef blargg_long sap_time_t; // clock cycle count
 typedef unsigned sap_addr_t; // 16-bit address
-enum { future_sap_time = LONG_MAX / 2 + 1 };
+enum { future_sap_time = INT_MAX / 2 + 1 };
 
 class Sap_Cpu {
 public:
--- a/src/flacng/flacng.h	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/flacng/flacng.h	Wed Dec 19 12:23:30 2007 +0200
@@ -25,7 +25,7 @@
 #include <audacious/main.h>
 #include <audacious/i18n.h>
 
-#define OUTPUT_BLOCK_SIZE (8192u)
+#define OUTPUT_BLOCK_SIZE (1024u)
 #define MAX_SUPPORTED_CHANNELS (2u)
 #define BUFFER_SIZE_SAMP (FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS)
 #define BUFFER_SIZE_BYTE (BUFFER_SIZE_SAMP * (FLAC__MAX_BITS_PER_SAMPLE/8))
--- a/src/madplug/plugin.c	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/madplug/plugin.c	Wed Dec 19 12:23:30 2007 +0200
@@ -610,7 +610,6 @@
 {
     Tuple *tuple = NULL;
     gchar *string = NULL;
-    gchar *realfn = NULL;
 
     struct id3_file *id3file = NULL;
     struct id3_tag *tag = NULL;
@@ -709,11 +708,10 @@
                 g_free(string);
                 string = NULL;
             }
-            realfn = g_filename_from_uri(filename, NULL, NULL);
-            __set_and_free(tuple, FIELD_FILE_NAME, NULL, g_path_get_basename(realfn ? realfn : filename));
-            __set_and_free(tuple, FIELD_FILE_PATH, NULL, g_path_get_dirname(realfn ? realfn : filename));
-            aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(realfn ? realfn : filename));
-            g_free(realfn); realfn = NULL;
+
+            __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename));
+            __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename));
+            aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename));
 
             // length
             length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
@@ -734,11 +732,9 @@
         id3_file_close(id3file);
     } // id3file
     else { // no id3tag
-        realfn = g_filename_from_uri(filename, NULL, NULL);
-        __set_and_free(tuple, FIELD_FILE_NAME, NULL, g_path_get_basename(realfn ? realfn : filename));
-        __set_and_free(tuple, FIELD_FILE_PATH, NULL, g_path_get_dirname(realfn ? realfn : filename));
-        aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(realfn ? realfn : filename));
-        g_free(realfn); realfn = NULL;
+        __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename));
+        __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename));
+        aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename));
         // length
         length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
         aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, length);
--- a/src/projectm-1.0/Makefile	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/projectm-1.0/Makefile	Wed Dec 19 12:23:30 2007 +0200
@@ -1,7 +1,6 @@
 PLUGIN = projectm-1.0${PLUGIN_SUFFIX}
 
 SRCS = main.cxx		\
-       video_init.cxx   \
        ConfigFile.cxx   \
        main_visplugin.c
 
--- a/src/projectm-1.0/main.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/projectm-1.0/main.cxx	Wed Dec 19 12:23:30 2007 +0200
@@ -1,30 +1,11 @@
-/* 
-projectM v1.01 - xmms-projectm.sourceforge.net
---------------------------------------------------
-
-Lead Developers:  Carmelo Piccione (carmelo.piccione@gmail.com) &
-                  Peter Sperl (peter@sperl.com)
-
-We have also been advised by some professors at CMU, namely Roger B. Dannenberg.
-http://www-2.cs.cmu.edu/~rbd/    
-  
-The inspiration for this program was Milkdrop by Ryan Geiss. Obviously. 
-
-This code is distributed under the GPL.
-
-
-THANKS FOR THE CODE!!!
--------------------------------------------------
-The base for this program was andy@nobugs.org's XMMS plugin tutorial
-http://www.xmms.org/docs/vis-plugin.html
-
-We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code
-fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html
-
-and some beat detection code was inspired by Frederic Patin @
-www.gamedev.net/reference/programming/features/beatdetection/
-
-*/
+/*
+ * main.cxx: plugin glue to libprojectm
+ * Copyright (c) 2008 William Pitcock <nenolod@sacredspiral.co.uk>
+ * Portions copyright (c) 2004-2006 Peter Sperl
+ *
+ * This program is free software; you may distribute it under the terms
+ * of the GNU General Public License; version 2.
+ */
 
 #include <stdio.h>
 #include <string.h>
@@ -35,9 +16,11 @@
 #include <SDL/SDL.h>
 #include <SDL/SDL_thread.h>
 
-extern "C" {
+extern "C"
+{
 #include <audacious/util.h>
 #include <audacious/plugin.h>
+#include <audacious/playlist.h>
 #include <audacious/auddrct.h>
 }
 
@@ -47,416 +30,422 @@
 #include <libprojectM/projectM.hpp>
 
 #include "sdltoprojectM.h"
-#include "video_init.h"
 
 #include <GL/gl.h>
 #define CONFIG_FILE "/share/projectM/config.inp"
 
 // Forward declarations 
-extern "C" void projectM_xmms_init(void); 
+extern "C" void projectM_xmms_init(void);
 extern "C" void projectM_cleanup(void);
-extern "C" void projectM_about(void);
-extern "C" void projectM_configure(void);
-extern "C" void projectM_playback_start(void);
-extern "C" void projectM_playback_stop(void);
 extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]);
-extern "C" void projectM_render_freq(gint16 pcm_data[2][256]);
-extern "C" int worker_func(void*);
+extern "C" int worker_func(void *);
 std::string read_config();
-void saveSnapshotToFile();
 
 extern "C" VisPlugin projectM_vtable;
 
-//extern preset_t * active_preset;
+int SDLThreadWrapper(void *);
+void handle_playback_trigger(void *, void *);
+
+class projectMPlugin
+{
+  private:
+    projectM *pm;
+
+    gint wvw, wvh, fvw, fvh;
+    gboolean fullscreen;
+    gboolean error;
 
-//FILE * debugFile = fopen("./dwrite-dump", "wb");
+    SDL_Event event;
+    SDL_Surface *screen;
+    SDL_Thread *worker_thread;
+    SDL_sem *sem;
+
+  public:
+    projectMPlugin()
+    {
+        std::string configFile = read_config();
+        ConfigFile config(configFile);
+
+        this->wvw = config.read<int>("Window Width", 512);
+        this->wvh = config.read<int>("Window Height", 512);
+
+        this->fullscreen = FALSE;
+        if (config.read("Fullscreen", true))
+              this->fullscreen = TRUE;
 
-// Our worker thread
-SDL_Thread *worker_thread = NULL;
-SDL_sem *sem = NULL;
-SDL_Event event;
+        /* initialise SDL */
+        if (SDL_Init(SDL_INIT_VIDEO) < 0)
+        {
+            this->error++;
+            return;
+        }
+
+        SDL_WM_SetCaption("projectM", "audacious");
+        SDL_EnableUNICODE(1);
+
+        this->sem = SDL_CreateSemaphore(0);
+
+        /* XXX */
+        aud_hook_associate("playback begin", handle_playback_trigger, NULL);
+    }
 
-SDL_Surface *screen;
+    ~projectMPlugin()
+    {
+        if (!this->sem)
+            return;
+
+        SDL_SemWait(this->sem);
+
+        if (this->worker_thread)
+            SDL_WaitThread(this->worker_thread, NULL);
 
+        SDL_DestroySemaphore(this->sem);
+        SDL_Quit();
 
-projectM * globalPM = NULL;
+        this->sem = 0;
+        this->worker_thread = 0;
+
+        delete this->pm;
+        this->pm = 0;
+
+        aud_hook_dissociate("playback begin", handle_playback_trigger);
+    }
 
-int maxsamples=512;
+    int run(void *unused)
+    {
+        if (error)
+            return -1;
+
+        std::string configFile = read_config();
+        this->initDisplay(this->wvw, this->wvh, &this->fvw, &this->fvh, this->fullscreen);
+        this->pm = new projectM(configFile);
+        this->pm->projectM_resetGL(this->wvw, this->wvh);
+
+        SDL_SemPost(this->sem);
+
+        while (SDL_SemValue(this->sem) == 1)
+        {
+            projectMEvent evt;
+            projectMKeycode key;
+            projectMModifier mod;
+
+            SDL_Event event;
+            while (SDL_PollEvent(&event))
+            {
+                evt = sdl2pmEvent(event);
+
+                key = sdl2pmKeycode(event.key.keysym.sym);
+                mod = sdl2pmModifier(event.key.keysym.mod);
+
+                switch (evt)
+                {
+                  case PROJECTM_KEYDOWN:
+                      switch (key)
+                      {
+                        case PROJECTM_K_c:
+                            this->takeScreenshot();
+                            break;
 
-int texsize=512;
-int gx=32,gy=24;
-int wvw=400,wvh=400;
-int fvw=1024,fvh=768;
-int fps=35, fullscreen=0;
+                        case PROJECTM_K_f:
+                            int w, h;
+                            if (fullscreen == 0)
+                            {
+                                w = fvw;
+                                h = fvh;
+                                fullscreen = 1;
+                            }
+                            else
+                            {
+                                w = wvw;
+                                h = wvh;
+                                fullscreen = 0;
+                            }
 
-// char *title;
+                            this->resizeDisplay(w, h, fullscreen);
+                            this->pm->projectM_resetGL(w, h);
+
+                            break;
+
+                        default:
+                            this->pm->key_handler(evt, key, mod);
+                            break;
+                      }
 
-gint disable_projectm(void *something) {
-	projectM_vtable.disable_plugin(&projectM_vtable);
-	return 0;
-}
+                      break;
+
+                  case PROJECTM_VIDEORESIZE:
+                      wvw = event.resize.w;
+                      wvh = event.resize.h;
+                      this->resizeDisplay(wvw, wvh, fullscreen);
+                      this->pm->projectM_resetGL(wvw, wvh);
+
+                      break;
 
-Uint32 get_xmms_title(Uint32 something, void *somethingelse) {
-	static char check_title = 1;
-	static int last_pos;
-	static char *last_title = NULL;
-	int pos;
-	char *title = NULL;
+                  case PROJECTM_VIDEOQUIT:
+                      std::cerr << "XXX: PROJECTM_VIDEOQUIT is not implemented yet!" << std::endl;
+                      break;
+
+                  default:
+                      break;
+                }
+            }
+
+            this->pm->renderFrame();
+
+            SDL_GL_SwapBuffers();
+        }
+
+        return 0;
+    }
+
+    void launchThread()
+    {
+        /* SDL sucks and won't let you use C++ functors... */
+        this->worker_thread = SDL_CreateThread(SDLThreadWrapper, NULL);
+    }
+
+    void addPCMData(gint16 pcm_data[2][512])
+    {
+        if (SDL_SemValue(this->sem) == 1)
+            this->pm->pcm->addPCM16(pcm_data);
+    }
 
-	//Nice optimization, but we want the title no matter what so I can display it when the song changes
-#if 0
-	if(!(globalPM->showtitle%2)) {
-		/* Repeat less often when not showing title */
-		return 1000;
-	}
-#endif
+    void initDisplay(gint width, gint height, gint *rwidth, gint *rheight, gboolean fullscreen)
+    {
+        this->wvw = width;
+        this->wvh = height;
+        this->fvw = *rwidth;
+        this->fvw = *rheight;
+        this->fullscreen = fullscreen;
+
+        const SDL_VideoInfo *info = NULL;
+        int bpp;
+        int flags;
+
+        info = SDL_GetVideoInfo();
+        if (!info)
+        {
+            this->error++;
+            return;
+        }
+
+        /* initialize fullscreen resolution to something "sane" */
+        *rwidth = width;
+        *rheight = height;
+
+        bpp = info->vfmt->BitsPerPixel;
+        SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+        if (this->fullscreen)
+            flags = SDL_OPENGL | SDL_HWSURFACE | SDL_FULLSCREEN;
+        else
+            flags = SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE;
+
+        this->screen = SDL_SetVideoMode(width, height, bpp, flags);
+        if (!this->screen)
+            this->error++;
+    }
 
-        pos = audacious_drct_pl_get_pos();
-	/* Only check every 1 second for title change, otherwise check pos */
-	if(check_title || pos != last_pos) {
-                title = audacious_drct_pl_get_title(pos);
-		if(title && (!last_title || strcmp(last_title,title))) {
-		  //globalPM->renderer->title = title;
-			//globalPM->renderer->drawtitle = 1;
+    void resizeDisplay(gint width, gint height, gboolean fullscreen)
+    {
+        this->fullscreen = fullscreen;
+
+        int flags;
+
+        if (this->fullscreen)
+            flags = SDL_OPENGL | SDL_HWSURFACE | SDL_FULLSCREEN;
+        else
+            flags = SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE;
+
+        this->screen = SDL_SetVideoMode(width, height, 0, flags);
+        if (this->screen == 0)
+            return;
+
+        SDL_ShowCursor(this->fullscreen ? SDL_DISABLE : SDL_ENABLE);
+    }
+
+    void triggerPlaybackBegin(PlaylistEntry *entry)
+    {
+        std::string title(entry->title);
+        this->pm->projectM_setTitle(title);
+    }
+
+    void takeScreenshot(void)
+    {
+        static int frame = 1;
+
+        std::string dumpPath(g_get_home_dir());
+        dumpPath.append("/.projectM/");
+
+        gchar *frame_ = g_strdup_printf("%.8d.bmp", frame);
+        dumpPath.append(frame_);
+        g_free(frame_);
 
-		  std::string titlepp(title);
-		  globalPM->projectM_setTitle(titlepp);
-			g_free(last_title);
-			last_title = title;
-		} else if(title && last_title != title) {
-			/* New copy of last title */
-			g_free(title);
-		}
-		check_title = !check_title;
-	}
-	last_pos = pos;
-	/* Repeat every 500ms */
-	return 500;
+        SDL_Surface *bitmap;
+
+        GLint viewport[4];
+        long bytewidth;
+        GLint width, height;
+        long bytes;
+
+        glReadBuffer(GL_FRONT);
+        glGetIntegerv(GL_VIEWPORT, viewport);
+
+        width = viewport[2];
+        height = viewport[3];
+
+        bytewidth = width * 4;
+        bytewidth = (bytewidth + 3) & ~3;
+        bytes = bytewidth * height;
+
+        bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0, 0, 0, 0);
+        glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap->pixels);
+
+        SDL_SaveBMP(bitmap, dumpPath.c_str());
+
+        SDL_FreeSurface(bitmap);
+
+        frame++;
+    }
+};
+
+/* glue to implementation section */
+projectMPlugin *thePlugin = 0;
+
+/* SDL sucks and won't let you use proper C++ functors. :( */
+int SDLThreadWrapper(void *unused)
+{
+    return thePlugin->run(unused);
 }
 
-int capture = 0;
-
-int worker_func(void*)
-{ 
-// char projectM_data[1024]; 
- SDL_TimerID title_timer = NULL;
- std::string config_file;
- config_file = read_config();
- ConfigFile config(config_file);
-
- int wvw = config.read<int>( "Window Width", 512 );
- int wvh = config.read<int>( "Window Height", 512 );
-
- int fullscreen = 0;
- if (config.read("Fullscreen", true)) fullscreen = 1;
-      else fullscreen = 0;
-
-  init_display(wvw,wvh,&fvw,&fvh,fullscreen); 
-  SDL_WM_SetCaption("projectM v1.00", "projectM v1.00");
-
-  /** Initialise projectM */
-    
-  globalPM = new projectM(config_file);
-  SDL_SemPost(sem);
-  title_timer = SDL_AddTimer(500, get_xmms_title, NULL);
-    /** Initialise the thread */
-  // SDL_SemTryWait(sem);
-  while ( SDL_SemValue(sem)==1 ) {
-        projectMEvent evt;
-        projectMKeycode key;
-        projectMModifier mod;
-
-        /** Process SDL events */
-        SDL_Event event;
-        while ( SDL_PollEvent( &event ) ) {
-            /** Translate into projectM codes and process */
-            evt = sdl2pmEvent( event );	  
-
-            key = sdl2pmKeycode( event.key.keysym.sym );
-            mod = sdl2pmModifier( event.key.keysym.mod );
-
-            if ( evt == PROJECTM_KEYDOWN ) {                 
-	   
-	      if(key == PROJECTM_K_c)
-		{
-		  //SDL_SaveBMP(screen, "/home/pete/1.bmp");
-		  saveSnapshotToFile();
-		}
-	      if(key == PROJECTM_K_v)
-		{
-		  // capture++;
-		}
-	      if(key == PROJECTM_K_f)
-		{
-		 
+void handle_playback_trigger(gpointer plentry_p, gpointer unused)
+{
+    PlaylistEntry *entry = reinterpret_cast<PlaylistEntry *>(plentry_p);
 
-		 int w, h;
-                    if (fullscreen == 0) {
-                        w = fvw;
-                        h = fvh;
-			fullscreen = 1;
-                    } else {
-                        w = wvw;
-                        h = wvh;
-			fullscreen = 0;
-                    }
-                  
-                    resize_display(w, h, fullscreen);
-                    globalPM->projectM_resetGL( w, h ); 
-                }
-	      else  globalPM->key_handler(evt,key,mod);
-
-              }
-	    else if ( evt == PROJECTM_VIDEORESIZE )
-	      {
-
-	       
+    if (!thePlugin)
+        return;
 
-		wvw=event.resize.w;
-		wvh=event.resize.h;
-	       
-		
-		resize_display(wvw,wvh,fullscreen);
-		globalPM->projectM_resetGL( wvw, wvh ); 
- 
-              } 
-	    else if ( evt == PROJECTM_VIDEOQUIT ) {
-	      
-	      (void) g_idle_add ((GSourceFunc) disable_projectm, NULL);
-	    }
-	}
-	
-        /** Add the waveform data */
-      
-
-        /** Render the new frame */
-	//	 strcpy(title,xmms_remote_get_playlist_title(projectM_vtable.xmms_session, xmms_remote_get_playlist_pos(projectM_vtable.xmms_session))); 
-
-	 //printf("%s\n",title);
-	// strcpy(globalPM->title,title);
-	
-	  globalPM->renderFrame();
-	
-      
-
-        SDL_GL_SwapBuffers();
-
-	if (capture % 2 == 1) saveSnapshotToFile();
-	//	SDL_SemPost(sem);
-      }
-
- if(title_timer) 
-  	SDL_RemoveTimer(title_timer);
- delete globalPM;
-
-
- return 0;
+    thePlugin->triggerPlaybackBegin(entry);
 }
 
-extern "C" void projectM_xmms_init(void) 
+extern "C" void projectM_xmms_init(void)
 {
-  
-  /* First, initialize SDL's video subsystem. */
- // std::cerr << "sdl init begin" << std::endl;  
-  if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 ) {
-    /* Failed, exit. */
-    fprintf( stderr, "Video initialization failed: %s\n",
-             SDL_GetError( ) );
-    //projectM_vtable.disable_plugin (&projectM_vtable);
-    return;
-    
-  }
-  sem = SDL_CreateSemaphore(0);
- // printf("projectM plugin: Initializing\n");
- 
-  SDL_EnableUNICODE(1);
-  
-  worker_thread = SDL_CreateThread ( *worker_func, NULL);
- 
+    thePlugin = new projectMPlugin;
+    thePlugin->launchThread();
 }
 
-
-
 extern "C" void projectM_cleanup(void)
 {
-
-  if(!sem) return;
-  SDL_SemWait(sem);
-  if(worker_thread) SDL_WaitThread(worker_thread, NULL);
-  // SDL_KillThread(worker_thread);
-  //printf("killed thread\n");
+    if (!thePlugin)
+        return;
 
-  SDL_DestroySemaphore(sem);
-  //printf("Destroy Mutex\n");
-  SDL_Quit();
-
-  sem = NULL;
-  worker_thread = NULL;
-  
- // printf("projectM plugin: Cleanup completed\n");
+    delete thePlugin;
 }
-extern "C" void projectM_about(void)
-{
-  printf("projectM plugin: About\n");
-}
-extern "C" void projectM_configure(void)
-{
-  printf("projectM plugin: Configure\n");
-}
-extern "C" void projectM_playback_start(void)
-{//thread_control = GO;
-  printf("projectM plugin: Playback starting\n");
-}
-extern "C" void projectM_playback_stop(void)
-{//thread_control = STOP;
-  printf("projectM plugin: Playback stopping\n");
-}
+
 extern "C" void projectM_render_pcm(gint16 pcm_data[2][512])
 {
-  //SDL_mutexP(mutex); while ( SDL_SemValue(sem)==1 )
-  if ( SDL_SemValue(sem)==1 )
-        globalPM->pcm->addPCM16(pcm_data);
-	 
-       	//SDL_mutexV(mutex);
-	
+    if (!thePlugin)
+        return;
+
+    thePlugin->addPCMData(pcm_data);
 }
 
-extern "C" void projectM_render_freq(gint16 freq_data[2][256])
-{
-  printf("NO GOOD\n");
- }
-
+/********************************************************************************
+ * XXX: This code is from projectM and still needs to be rewritten!             *
+ ********************************************************************************/
 std::string read_config()
 {
 
 //   int n;
-   
-   char num[512];
-   FILE *in; 
-   FILE *out;
-
-   char* home;
-   char projectM_home[1024];
-   char projectM_config[1024];
-
-   strcpy(projectM_config, PROJECTM_PREFIX);
-   strcpy(projectM_config+strlen(PROJECTM_PREFIX), CONFIG_FILE);
-   projectM_config[strlen(PROJECTM_PREFIX)+strlen(CONFIG_FILE)]='\0';
-   //printf("dir:%s \n",projectM_config);
-   home=getenv("HOME");
-   strcpy(projectM_home, home);
-   strcpy(projectM_home+strlen(home), "/.projectM/config.inp");
-   projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0';
 
-  
- if ((in = fopen(projectM_home, "r")) != 0) 
-   {
-     //printf("reading ~/.projectM/config.inp \n");
-     fclose(in);
-     return std::string(projectM_home);
-   }
- else
-   {
-     printf("trying to create ~/.projectM/config.inp \n");
+    char num[512];
+    FILE *in;
+    FILE *out;
 
-     strcpy(projectM_home, home);
-     strcpy(projectM_home+strlen(home), "/.projectM");
-     projectM_home[strlen(home)+strlen("/.projectM")]='\0';
-     mkdir(projectM_home,0755);
-
-     strcpy(projectM_home, home);
-     strcpy(projectM_home+strlen(home), "/.projectM/config.inp");
-     projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0';
+    char *home;
+    char projectM_home[1024];
+    char projectM_config[1024];
 
-     if((out = fopen(projectM_home,"w"))!=0)
-       {
-	
-	 if ((in = fopen(projectM_config, "r")) != 0) 
-	   {
-
-	     while(fgets(num,80,in)!=NULL)
-	       {
-		 fputs(num,out);
-	       }
-	     fclose(in);
-	     fclose(out);
-	    
-
-	     if ((in = fopen(projectM_home, "r")) != 0) 
-	       { 
-		 printf("created ~/.projectM/config.inp successfully\n");  
-		 fclose(in);
-		 return std::string(projectM_home);
-	       }
-	     else{printf("This shouldn't happen, using implementation defualts\n");abort();}
-	   }
-	 else{printf("Cannot find projectM default config, using implementation defaults\n");abort();}
-       }
-     else
-       {
-	 printf("Cannot create ~/.projectM/config.inp, using default config file\n");
-	 if ((in = fopen(projectM_config, "r")) != 0) 
-	   { printf("Successfully opened default config file\n");
-	     fclose(in);
-	     return std::string(projectM_config);}
-	 else{ printf("Using implementation defaults, your system is really messed up, I'm suprised we even got this far\n");  abort();}
-       }
-
-   }
-
- abort();
-}
-
-int frame = 1;
+    strcpy(projectM_config, PROJECTM_PREFIX);
+    strcpy(projectM_config + strlen(PROJECTM_PREFIX), CONFIG_FILE);
+    projectM_config[strlen(PROJECTM_PREFIX) + strlen(CONFIG_FILE)] = '\0';
+    //printf("dir:%s \n",projectM_config);
+    home = getenv("HOME");
+    strcpy(projectM_home, home);
+    strcpy(projectM_home + strlen(home), "/.projectM/config.inp");
+    projectM_home[strlen(home) + strlen("/.projectM/config.inp")] = '\0';
 
 
-void saveSnapshotToFile()
-{
-  char dumpPath[512];
-  char Home[512];
-  //char *home;
-  
-  SDL_Surface *	bitmap;
-  
-  GLint		viewport[4];
-  long		bytewidth;
-  GLint		width, height;
-  long		bytes;
-  
-  glReadBuffer(GL_FRONT);
-  glGetIntegerv(GL_VIEWPORT, viewport);
-  
-  width = viewport[2];
-  height = viewport[3];
-            
-  bytewidth = width * 4;
-  bytewidth = (bytewidth + 3) & ~3;
-  bytes = bytewidth * height;
-  
-  /*
-    glFinish();
-    glPixelStorei(GL_PACK_ALIGNMENT, 4);
-    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
-    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
-    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
-  */
-  
-  
-  bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, width,  height, 32,0,0,0,0);
-  glReadPixels(0, 0, width, height,
-	       GL_BGRA,
-	       GL_UNSIGNED_INT_8_8_8_8_REV,
-	       bitmap->pixels);
-  
-  sprintf(dumpPath, "/.projectM/%.8d.bmp", frame++);
-  // home=getenv("HOME");
-  strcpy(Home, getenv("HOME"));
-  strcpy(Home+strlen(Home), dumpPath);
-  Home[strlen(Home)]='\0';
-  SDL_SaveBMP(bitmap, Home);
-     
-  SDL_FreeSurface(bitmap);
- 
-       
+    if ((in = fopen(projectM_home, "r")) != 0)
+    {
+        //printf("reading ~/.projectM/config.inp \n");
+        fclose(in);
+        return std::string(projectM_home);
+    }
+    else
+    {
+        printf("trying to create ~/.projectM/config.inp \n");
+
+        strcpy(projectM_home, home);
+        strcpy(projectM_home + strlen(home), "/.projectM");
+        projectM_home[strlen(home) + strlen("/.projectM")] = '\0';
+        mkdir(projectM_home, 0755);
+
+        strcpy(projectM_home, home);
+        strcpy(projectM_home + strlen(home), "/.projectM/config.inp");
+        projectM_home[strlen(home) + strlen("/.projectM/config.inp")] = '\0';
+
+        if ((out = fopen(projectM_home, "w")) != 0)
+        {
+
+            if ((in = fopen(projectM_config, "r")) != 0)
+            {
+
+                while (fgets(num, 80, in) != NULL)
+                {
+                    fputs(num, out);
+                }
+                fclose(in);
+                fclose(out);
+
+
+                if ((in = fopen(projectM_home, "r")) != 0)
+                {
+                    printf("created ~/.projectM/config.inp successfully\n");
+                    fclose(in);
+                    return std::string(projectM_home);
+                }
+                else
+                {
+                    printf("This shouldn't happen, using implementation defualts\n");
+                    abort();
+                }
+            }
+            else
+            {
+                printf("Cannot find projectM default config, using implementation defaults\n");
+                abort();
+            }
+        }
+        else
+        {
+            printf("Cannot create ~/.projectM/config.inp, using default config file\n");
+            if ((in = fopen(projectM_config, "r")) != 0)
+            {
+                printf("Successfully opened default config file\n");
+                fclose(in);
+                return std::string(projectM_config);
+            }
+            else
+            {
+                printf("Using implementation defaults, your system is really messed up, I'm suprised we even got this far\n");
+                abort();
+            }
+        }
+
+    }
+
+    abort();
 }
-
--- a/src/projectm-1.0/main_visplugin.c	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/projectm-1.0/main_visplugin.c	Wed Dec 19 12:23:30 2007 +0200
@@ -2,24 +2,14 @@
 
 extern void projectM_xmms_init(void);
 extern void projectM_cleanup(void);
-extern void projectM_about(void);
-extern void projectM_configure(void);
-extern void projectM_playback_start(void);
-extern void projectM_playback_stop(void);
 extern void projectM_render_pcm(gint16 pcm_data[2][512]);
-extern void projectM_render_freq(gint16 pcm_data[2][256]);
 
 VisPlugin projectM_vtable = {
     .description = "projectM v1.0",
     .num_pcm_chs_wanted = 2,
     .init = projectM_xmms_init,
     .cleanup = projectM_cleanup,
-    .about = projectM_about,
-    .configure = projectM_configure,
-    .playback_start = projectM_playback_start,
-    .playback_stop = projectM_playback_stop,
     .render_pcm = projectM_render_pcm,
-    .render_freq = projectM_render_freq,
 };
 
 VisPlugin *projectM_vplist[] = { &projectM_vtable, NULL };
--- a/src/projectm-1.0/video_init.cxx	Wed Dec 19 12:21:59 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-//video_init.c - SDL/Opengl Windowing Creation/Resizing Functions
-//
-//by Peter Sperl
-//
-//Opens an SDL Window and creates an OpenGL session
-//also able to handle resizing and fullscreening of windows
-//just call init_display again with differant variables
-
-#include <SDL/SDL.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#include "video_init.h"
-#include <iostream>
-extern SDL_Surface *screen;
-extern int texsize;
-
-void resize_display(int w, int h, int f) {
-  int flags;
-  if (f) flags =  SDL_OPENGL|SDL_HWSURFACE|SDL_FULLSCREEN;
-  else   flags =  SDL_OPENGL|SDL_HWSURFACE|SDL_RESIZABLE;
-//  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
-  screen = SDL_SetVideoMode( w, h, 0, flags ) ;
-  if(screen == 0 ) {
-      fprintf( stderr, "Video mode set failed: %s\n", SDL_GetError( ) );
-      return;
-  }
-  
-  SDL_ShowCursor(f ? SDL_DISABLE : SDL_ENABLE);
-}
-
-//init_display
-//
-//Sets screen to new width and height (w,h)
-//Also switches between fullscreen and windowed
-//with the boolean f (fullscreen)
-void init_display(int w, int h, int *fvw, int *fvh, int f)
-{
-  
-  /* Information about the current video settings. */
-  const SDL_VideoInfo* info = NULL;
-  int bpp = 0;
-  /* Flags we will pass into SDL_SetVideoMode. */
-  int flags = 0;
-
-
-  /* Let's get some video information. */
-  info = SDL_GetVideoInfo( );
-  if( !info ) {
-    /* This should probably never happen. */
-    fprintf( stderr, "Video query failed: %s\n",
-             SDL_GetError( ) );
-    //    projectM_vtable.disable_plugin (&projectM_vtable);
-    return;
-  }
-  
-//  printf("Screen Resolution: %d x %d\n", info->current_w, info->current_h);
-// XXX
-  *fvw = w;
-  *fvh = h;
-  bpp = info->vfmt->BitsPerPixel;
-  //SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
-  //SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
-  //SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
-
-  // SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 8 );
-  //  SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 8 );
-  //  SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 8 );
-  SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
-  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
-  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
-  if (f==0)
-     flags = SDL_OPENGL|SDL_HWSURFACE|SDL_RESIZABLE;
-  else flags = SDL_OPENGL|SDL_HWSURFACE|SDL_FULLSCREEN;
- screen= SDL_SetVideoMode( w, h, bpp, flags ) ;
-  if(screen == 0 ) {
-    /* 
-     * This could happen for a variety of reasons,
-     * including DISPLAY not being set, the specified
-     * resolution not being available, etc.
-     */
-   fprintf( stderr, "Video mode set failed: %s\n",
-	     SDL_GetError( ) );
-    
-   // projectM_vtable.disable_plugin (&projectM_vtable);
-    return;
-    
-  }
-  
-  // setup_opengl(w,h);
-  //gluOrtho2D(0, w, 0, h);
-}
-
-
--- a/src/projectm-1.0/video_init.h	Wed Dec 19 12:21:59 2007 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
- 
- void init_display( int w, int h, int *fvw, int *fvh, int fullscreen );
- void resize_display( int w, int h, int fullscreen );
-
-
--- a/src/rootvis/config_frontend_widgets.c	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/rootvis/config_frontend_widgets.c	Wed Dec 19 12:23:30 2007 +0200
@@ -371,8 +371,7 @@
 
 	{
 		GtkWidget *vbox_0, *notebook_1, *button_box_1,
-			*vbox_2[4], *frame_3[4], *vbox_3[1], *hbox_4[5],
-			*check_debug, *check_stereo,
+			*vbox_2[4], *frame_3[4], *hbox_4[5],
 			*close_button, *revert_button;
 
 		vbox_0 = frontend_create_box(VBOX, window, "rootvis_config_vbox", ATTACH_TO_CONTAINER);
@@ -427,7 +426,7 @@
 {
 	GtkWidget *window, *channel_button[2],
 		  *button_box[2], *channels_frame, *main_frame, *vbox,
-		  *main_vbox, *channels_hbox, *channel_vbox[2],
+		  *main_vbox, *channel_vbox[2],
 		  *save_button, *revert_button, *close_button;
 
 	window = frontend_create_window(GTK_WINDOW_TOPLEVEL, "Main");
--- a/src/rootvis/rootvis.c	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/rootvis/rootvis.c	Wed Dec 19 12:23:30 2007 +0200
@@ -13,7 +13,6 @@
 // Forward declarations
 static void rootvis_init(void);
 static void rootvis_cleanup(void);
-static void rootvis_about(void);
 static void rootvis_configure(void);
 static void rootvis_playback_start(void);
 static void rootvis_playback_stop(void);
@@ -416,11 +415,6 @@
   }
 }
 
-static void rootvis_about(void)
-{
-	print_status("About");
-}
-
 static void rootvis_configure(void)
 {
 	print_status("Configuration trigger");
--- a/src/xspf/xspf.c	Wed Dec 19 12:21:59 2007 +0200
+++ b/src/xspf/xspf.c	Wed Dec 19 12:23:30 2007 +0200
@@ -76,6 +76,7 @@
     { FIELD_YEAR,         "year",         TUPLE_INT,      TRUE,   CMP_DEF },
     { FIELD_DATE,         "date",         TUPLE_STRING,   TRUE,   CMP_DEF },
     { FIELD_GENRE,        "genre",        TUPLE_STRING,   TRUE,   CMP_DEF },
+    { FIELD_MTIME,        "mtime",        TUPLE_INT,      TRUE,   CMP_DEF },
     { FIELD_FORMATTER,    "formatter",    TUPLE_STRING,   TRUE,   CMP_DEF },
 };
 
@@ -165,6 +166,7 @@
                             break;
                         
                         case TUPLE_INT:
+                            AUDDBG("field=%s val=%s\n", xspf_entries[i].xspfName, str);
                             aud_tuple_associate_int(tuple, xspf_entries[i].tupleField, NULL, atol((char *)str));
                             break;
                         
@@ -181,29 +183,24 @@
     }
 
     if (location) {
-        gchar *realfn = NULL, *scratch = NULL;
+        gchar *scratch = NULL;
 
         /* filename and path in tuple must be unescaped. */
-        scratch = g_filename_from_uri(location, NULL, NULL);
-        realfn = aud_str_to_utf8(scratch ? scratch : location);
-        g_free(scratch);
-
-        scratch = g_path_get_basename(realfn);
+        scratch = aud_uri_to_display_basename(location);
         aud_tuple_associate_string(tuple, FIELD_FILE_NAME, NULL, scratch);
         g_free(scratch);
 
-        scratch = g_path_get_dirname(realfn);
+        scratch = aud_uri_to_display_dirname(location);
         aud_tuple_associate_string(tuple, FIELD_FILE_PATH, NULL, scratch);
         g_free(scratch);
 
-        aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, strrchr(realfn, '.'));
+        aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, strrchr(location, '.'));
 
         AUDDBG("tuple->file_name = %s\n", aud_tuple_get_string(tuple, FIELD_FILE_NAME, NULL));
         AUDDBG("tuple->file_path = %s\n", aud_tuple_get_string(tuple, FIELD_FILE_PATH, NULL));
 
         /* add file to playlist */
         aud_playlist_load_ins_file_tuple(playlist, location, filename, pos, tuple);
-        g_free(realfn);
         pos++;
     }
 
@@ -520,9 +517,6 @@
                     xspf_add_node(track, xs->type, xs->isMeta, xs->xspfName, scratch, scratchi);
             }
 
-            /* Write mtime unconditionally to support staticlist */
-            xspf_add_node(track, TUPLE_INT, TRUE, "mtime", NULL,
-                aud_tuple_get_int(entry->tuple, FIELD_MTIME, NULL));
         } else {
 
             if (entry->title != NULL && g_utf8_validate(entry->title, -1, NULL))