changeset 1671:daabad781796 trunk

[svn] - amidi-plug 0.6 imported; among other improvements, multiple soundfont loading for fluidsynth backend and option to extract/display lyrics and comments contained in midi files
author giacomo
date Tue, 12 Sep 2006 10:59:59 -0700
parents 0abfd27b3849
children 600efc52c645
files ChangeLog Plugins/Input/amidi-plug/Makefile.in Plugins/Input/amidi-plug/amidi-plug.c Plugins/Input/amidi-plug/backend-alsa/Makefile.in Plugins/Input/amidi-plug/backend-dummy/Makefile.in Plugins/Input/amidi-plug/backend-fluidsynth/Makefile.in Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.c Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.h Plugins/Input/amidi-plug/i_backend.c Plugins/Input/amidi-plug/i_common.h Plugins/Input/amidi-plug/i_configure-alsa.c Plugins/Input/amidi-plug/i_configure-ap.c Plugins/Input/amidi-plug/i_configure-dummy.c Plugins/Input/amidi-plug/i_configure-fluidsynth.c Plugins/Input/amidi-plug/i_configure.c Plugins/Input/amidi-plug/i_configure.h Plugins/Input/amidi-plug/i_fileinfo.c Plugins/Input/amidi-plug/i_midi.c Plugins/Input/amidi-plug/i_midi.h Plugins/Input/amidi-plug/i_midievent.h Plugins/Input/amidi-plug/i_utils.c Plugins/Input/amidi-plug/i_utils.h configure.ac mk/rules.mk.in
diffstat 24 files changed, 634 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Sep 11 16:06:23 2006 -0700
+++ b/ChangeLog	Tue Sep 12 10:59:59 2006 -0700
@@ -1,3 +1,11 @@
+2006-09-11 23:06:23 +0000  Tony Vroon <chainsaw@gentoo.org>
+  revision [2277]
+  Use the VFS.
+
+  Changes:        Modified:
+  +5 -4           trunk/audacious/widgets/skin.c  
+
+
 2006-09-11 22:24:52 +0000  Tony Vroon <chainsaw@gentoo.org>
   revision [2275]
   fprintf implementation in the VFS common layer by Luca Barbato. Use it in the Container plugins.
--- a/Plugins/Input/amidi-plug/Makefile.in	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/Makefile.in	Tue Sep 12 10:59:59 2006 -0700
@@ -5,7 +5,8 @@
 SUBDIRS = pcfg @AMIDIPLUG_BACKENDS@
 
 noinst_HEADERS = amidi-plug.h i_backend.h i_midi.h i_midievent.h \
-                 i_configure.h i_configure-ap.h i_configure-alsa.h \
+                 i_configure.h i_configure_private.h \
+                 i_configure-ap.h i_configure-alsa.h \
                  i_configure-fluidsynth.h i_configure-dummy.h \
                  i_fileinfo.h i_utils.h i_common.h \
                  amidi-plug-icon.xpm amidi-plug.logo.xpm \
@@ -21,7 +22,7 @@
 
 OBJECTS = ${SOURCES:.c=.o}
 
-CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(GMODULE_CFLAGS) -DAMIDIPLUGDATADIR=\"$(AMIDIPLUGDATADIR)\" \
+CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(GMODULE_CFLAGS) -DAMIDIPLUGBACKENDDIR=\"$(AMIDIPLUGBACKENDDIR)\" \
           -I../../../intl -I../../..
 
 include ../../../mk/objective.mk
--- a/Plugins/Input/amidi-plug/amidi-plug.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/amidi-plug.c	Tue Sep 12 10:59:59 2006 -0700
@@ -361,7 +361,7 @@
     g_warning( "No sequencer backend selected\n" );
     i_message_gui( _("AMIDI-Plug - warning") ,
                    _("No sequencer backend has been selected!\nPlease configure AMIDI-Plug before playing.") ,
-                   AMIDIPLUG_MESSAGE_WARN , NULL );
+                   AMIDIPLUG_MESSAGE_WARN , NULL , TRUE );
     amidiplug_playing_status = AMIDIPLUG_ERR;
     return;
   }
@@ -582,6 +582,12 @@
         midifile.current_tempo = event->data.tempo;
         pthread_mutex_unlock(&amidiplug_gettime_mutex);
         break;
+      case SND_SEQ_EVENT_META_TEXT:
+        /* do nothing */
+        break;
+      case SND_SEQ_EVENT_META_LYRIC:
+        /* do nothing */
+        break;
       default:
         DEBUGMSG( "PLAY thread, encountered invalid event type %i\n" , event->type );
         break;
--- a/Plugins/Input/amidi-plug/backend-alsa/Makefile.in	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/backend-alsa/Makefile.in	Tue Sep 12 10:59:59 2006 -0700
@@ -5,7 +5,7 @@
 
 CFLAGS += $(PICFLAGS) $(GLIB_CFLAGS) $(ALSA_CFLAGS) -I../../../../intl -I../../../..
 
-libdir = $(AMIDIPLUGDATADIR)
+libdir = $(AMIDIPLUGBACKENDDIR)
 
 OBJECTIVE_LIBS = ap-alsa$(SHARED_SUFFIX)
 
--- a/Plugins/Input/amidi-plug/backend-dummy/Makefile.in	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/backend-dummy/Makefile.in	Tue Sep 12 10:59:59 2006 -0700
@@ -5,7 +5,7 @@
 
 CFLAGS += $(PICFLAGS) $(GLIB_CFLAGS) -I../../../../intl -I../../../..
 
-libdir = $(AMIDIPLUGDATADIR)
+libdir = $(AMIDIPLUGBACKENDDIR)
 
 OBJECTIVE_LIBS = ap-dummy$(SHARED_SUFFIX)
 
--- a/Plugins/Input/amidi-plug/backend-fluidsynth/Makefile.in	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/backend-fluidsynth/Makefile.in	Tue Sep 12 10:59:59 2006 -0700
@@ -5,7 +5,7 @@
 
 CFLAGS += $(PICFLAGS) $(GLIB_CFLAGS) $(FLUIDSYNTH_CFLAGS) -I../../../../intl -I../../../..
 
-libdir = $(AMIDIPLUGDATADIR)
+libdir = $(AMIDIPLUGBACKENDDIR)
 
 OBJECTIVE_LIBS = ap-fluidsynth$(SHARED_SUFFIX)
 
--- a/Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.c	Tue Sep 12 10:59:59 2006 -0700
@@ -32,7 +32,7 @@
   if ( name != NULL )
     *name = g_strdup( "fluidsynth" );
   if ( longname != NULL )
-    *longname = g_strdup( "FluidSynth Backend " AMIDIPLUG_VERSION );
+    *longname = g_strdup( "FluidSynth Backend " VERSION );
   if ( desc != NULL )
     *desc = g_strdup( _("This backend produces audio by sending MIDI events "
                         "to FluidSynth, a real-time software synthesizer based "
@@ -51,7 +51,7 @@
   /* read configuration options */
   i_cfg_read();
 
-  sc.soundfont_id = -1;
+  sc.soundfont_ids = g_array_new( FALSE , FALSE , sizeof(gint) );
   sc.sample_rate = amidiplug_cfg_fsyn.fsyn_synth_samplerate;
   sc.settings = new_fluid_settings();
 
@@ -81,8 +81,14 @@
 
 gint backend_cleanup( void )
 {
-  if ( sc.soundfont_id != -1 )
-    fluid_synth_sfunload( sc.synth , sc.soundfont_id , 0 );
+  if ( sc.soundfont_ids->len > 0 )
+  {
+    /* unload soundfonts */
+    gint i = 0;
+    for ( i = 0 ; i < sc.soundfont_ids->len ; i++ )
+      fluid_synth_sfunload( sc.synth , g_array_index( sc.soundfont_ids , gint , i ) , 0 );
+  }
+  g_array_free( sc.soundfont_ids , TRUE );
   delete_fluid_synth( sc.synth );
   delete_fluid_settings( sc.settings );
 
@@ -102,7 +108,7 @@
 gint sequencer_start( gchar * midi_fname )
 {
   /* soundfont loader, check if we should load soundfont on first midifile play */
-  if (( amidiplug_cfg_fsyn.fsyn_soundfont_load == 1 ) && (sc.soundfont_id == -1 ))
+  if (( amidiplug_cfg_fsyn.fsyn_soundfont_load == 1 ) && ( sc.soundfont_ids->len == 0 ))
     i_soundfont_load();
 
   return 1; /* success */
@@ -349,19 +355,29 @@
 {
   if ( strcmp( amidiplug_cfg_fsyn.fsyn_soundfont_file , "" ) )
   {
-    DEBUGMSG( "loading soundfont %s\n" , amidiplug_cfg_fsyn.fsyn_soundfont_file );
-    sc.soundfont_id = fluid_synth_sfload( sc.synth , amidiplug_cfg_fsyn.fsyn_soundfont_file , 0 );
-    if ( sc.soundfont_id == -1 )
-      g_warning( "unable to load SoundFont file %s\n" , amidiplug_cfg_fsyn.fsyn_soundfont_file );
-#ifdef DEBUG
-    else
-      DEBUGMSG( "soundfont %s successfully loaded\n" , amidiplug_cfg_fsyn.fsyn_soundfont_file );
-#endif
+    gchar **sffiles = g_strsplit( amidiplug_cfg_fsyn.fsyn_soundfont_file , ";" , 0 );
+    gint i = 0;
+    while ( sffiles[i] != NULL )
+    {
+      gint sf_id = 0;
+      DEBUGMSG( "loading soundfont %s\n" , sffiles[i] );
+      sf_id = fluid_synth_sfload( sc.synth , sffiles[i] , 0 );
+      if ( sf_id == -1 )
+      {
+        g_warning( "unable to load SoundFont file %s\n" , sffiles[i] );
+      }
+      else
+      {
+        DEBUGMSG( "soundfont %s successfully loaded\n" , sffiles[i] );
+        g_array_append_val( sc.soundfont_ids , sf_id );
+      }
+      i++;
+    }
+    g_strfreev( sffiles );
   }
   else
   {
     g_warning( "FluidSynth backend was selected, but no SoundFont has been specified\n" );
-    sc.soundfont_id = -1;
   }
 }
 
--- a/Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/backend-fluidsynth/b-fluidsynth.h	Tue Sep 12 10:59:59 2006 -0700
@@ -33,7 +33,7 @@
   fluid_settings_t * settings;
   fluid_synth_t * synth;
 
-  gint soundfont_id;
+  GArray *soundfont_ids;
 
   gint ppq;
   gdouble cur_microsec_per_tick;
--- a/Plugins/Input/amidi-plug/i_backend.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_backend.c	Tue Sep 12 10:59:59 2006 -0700
@@ -20,7 +20,6 @@
 
 #include "i_backend.h"
 
-
 gboolean i_str_has_pref_and_suff( const gchar *str , gchar *pref , gchar *suff )
 {
   if ( (g_str_has_prefix( str , pref )) &&
@@ -35,7 +34,7 @@
   GDir * backend_directory;
   GSList * backend_list = NULL;
 
-  backend_directory = g_dir_open( AMIDIPLUGDATADIR , 0 , NULL );
+  backend_directory = g_dir_open( AMIDIPLUGBACKENDDIR , 0 , NULL );
   if ( backend_directory != NULL )
   {
     const gchar * backend_directory_entry = g_dir_read_name( backend_directory );
@@ -46,7 +45,7 @@
       {
         GModule * module;
         gchar * (*getapmoduleinfo)( gchar ** , gchar ** , gchar ** , gint * );
-        gchar * module_pathfilename = g_strjoin( "" , AMIDIPLUGDATADIR , "/" ,
+        gchar * module_pathfilename = g_strjoin( "" , AMIDIPLUGBACKENDDIR , "/" ,
                                                  backend_directory_entry , NULL );
         /* seems to be a backend for amidi-plug , try to load it */
         module = g_module_open( module_pathfilename , 0 );
@@ -79,7 +78,7 @@
     g_dir_close( backend_directory );
   }
   else
-    g_warning( "Unable to open the backend directory %s\n" , AMIDIPLUGDATADIR );
+    g_warning( "Unable to open the backend directory %s\n" , AMIDIPLUGBACKENDDIR );
 
   return backend_list;
 }
@@ -103,7 +102,7 @@
 
 gint i_backend_load( gchar * module_name )
 {
-  gchar * module_pathfilename = g_strjoin( "" , AMIDIPLUGDATADIR , "/ap-" , module_name , ".so" , NULL );
+  gchar * module_pathfilename = g_strjoin( "" , AMIDIPLUGBACKENDDIR , "/ap-" , module_name , ".so" , NULL );
   DEBUGMSG( "loading backend '%s'\n" , module_pathfilename );
   backend.gmodule = g_module_open( module_pathfilename , 0 );
 
@@ -147,6 +146,7 @@
   }
   else
   {
+    backend.name = NULL;
     g_warning( "unable to load backend '%s'\n" , module_pathfilename );
     g_free( module_pathfilename );
     return 0;
--- a/Plugins/Input/amidi-plug/i_common.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_common.h	Tue Sep 12 10:59:59 2006 -0700
@@ -43,7 +43,7 @@
 #endif /* DEBUG */
 
 
-#define AMIDIPLUG_VERSION "0.5"
+#define AMIDIPLUG_VERSION "0.6"
 #define PLAYER_NAME "Audacious"
 #define PLAYER_LOCALRCDIR ".audacious"
 #define G_PATH_GET_BASENAME(x) g_path_get_basename(x)
--- a/Plugins/Input/amidi-plug/i_configure-alsa.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure-alsa.c	Tue Sep 12 10:59:59 2006 -0700
@@ -50,6 +50,7 @@
 };
 
 
+
 void i_configure_ev_portlv_changetoggle( GtkCellRendererToggle * rdtoggle ,
                                          gchar * path_str , gpointer data )
 {
@@ -342,7 +343,7 @@
     gtk_container_add( GTK_CONTAINER(port_lv_sw) , port_lv );
     gtk_container_add( GTK_CONTAINER(port_lv_frame) , port_lv_sw );
     gtk_box_pack_start( GTK_BOX(content_vbox) , port_lv_frame , TRUE , TRUE , 0 );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_portlv_commit) , port_lv );
 
     /* MIXER CARD/CONTROL COMBOBOXES */
@@ -408,9 +409,9 @@
     mixer_frame = gtk_frame_new( _("Mixer settings") );
     gtk_container_add( GTK_CONTAINER(mixer_frame) , mixer_table );
     gtk_box_pack_start( GTK_BOX(content_vbox) , mixer_frame , TRUE , TRUE , 0 );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_cardcmb_commit) , mixer_card_cmb );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_mixctlcmb_commit) , mixer_ctl_cmb );
 
     free_card_list( scards_h );
--- a/Plugins/Input/amidi-plug/i_configure-ap.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure-ap.c	Tue Sep 12 10:59:59 2006 -0700
@@ -115,12 +115,24 @@
 
 void i_configure_ev_settings_commit( gpointer settings_vbox )
 {
-  GtkWidget * settings_precalc_checkbt = g_object_get_data( G_OBJECT(settings_vbox) ,
-                                                            "ap_opts_length_precalc" );
+  GtkWidget *settings_precalc_checkbt = g_object_get_data( G_OBJECT(settings_vbox) ,
+                                                           "ap_opts_length_precalc" );
+  GtkWidget *settings_extractlyr_checkbt = g_object_get_data( G_OBJECT(settings_vbox) ,
+                                                              "ap_opts_lyrics_extract" );
+  GtkWidget *settings_extractcomm_checkbt = g_object_get_data( G_OBJECT(settings_vbox) ,
+                                                               "ap_opts_comments_extract" );
   if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(settings_precalc_checkbt) ) )
     amidiplug_cfg_ap.ap_opts_length_precalc = 1;
   else
     amidiplug_cfg_ap.ap_opts_length_precalc = 0;
+  if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(settings_extractlyr_checkbt) ) )
+    amidiplug_cfg_ap.ap_opts_lyrics_extract = 1;
+  else
+    amidiplug_cfg_ap.ap_opts_lyrics_extract = 0;
+  if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(settings_extractcomm_checkbt) ) )
+    amidiplug_cfg_ap.ap_opts_comments_extract = 1;
+  else
+    amidiplug_cfg_ap.ap_opts_comments_extract = 0;
   return;
 }
 
@@ -142,7 +154,8 @@
   GtkWidget *ap_page_vbox;
   GtkWidget *title_widget;
   GtkWidget *content_vbox; /* this vbox will contain two items of equal space (50%/50%) */
-  GtkWidget *settings_frame, *settings_vbox, *settings_precalc_checkbt;
+  GtkWidget *settings_frame, *settings_vbox;
+  GtkWidget *settings_precalc_checkbt, *settings_extractcomm_checkbt, *settings_extractlyr_checkbt;
   GtkWidget *backend_lv_frame, *backend_lv, *backend_lv_sw;
   GtkWidget *backend_lv_hbox, *backend_lv_vbbox, *backend_lv_infobt;
   GtkListStore *backend_store;
@@ -203,7 +216,7 @@
   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(backend_lv_sw) ,
                                   GTK_POLICY_NEVER , GTK_POLICY_ALWAYS );
   gtk_container_add( GTK_CONTAINER(backend_lv_sw) , backend_lv );
-  g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+  g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                             G_CALLBACK(i_configure_ev_backendlv_commit) , backend_lv );
 
   backend_lv_hbox = gtk_hbox_new( FALSE , 0 );
@@ -221,14 +234,27 @@
   settings_frame = gtk_frame_new( _("Advanced settings") );
   settings_vbox = gtk_vbox_new( FALSE , 0 );
   gtk_container_set_border_width( GTK_CONTAINER(settings_vbox), 4 );
-  settings_precalc_checkbt = gtk_check_button_new_with_label( _("pre-calculate length of MIDI files in playlist") );
+  settings_precalc_checkbt = gtk_check_button_new_with_label(
+                               _("pre-calculate length of MIDI files in playlist") );
   if ( amidiplug_cfg_ap.ap_opts_length_precalc )
     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(settings_precalc_checkbt) , TRUE );
   gtk_box_pack_start( GTK_BOX(settings_vbox) , settings_precalc_checkbt , FALSE , FALSE , 2 );
+  settings_extractcomm_checkbt = gtk_check_button_new_with_label(
+                                   _("extract comments from MIDI file (if available)") );
+  if ( amidiplug_cfg_ap.ap_opts_comments_extract )
+    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(settings_extractcomm_checkbt) , TRUE );
+  gtk_box_pack_start( GTK_BOX(settings_vbox) , settings_extractcomm_checkbt , FALSE , FALSE , 2 );
+  settings_extractlyr_checkbt = gtk_check_button_new_with_label(
+                                  _("extract lyrics from MIDI file (if available)") );
+  if ( amidiplug_cfg_ap.ap_opts_lyrics_extract )
+    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(settings_extractlyr_checkbt) , TRUE );
+  gtk_box_pack_start( GTK_BOX(settings_vbox) , settings_extractlyr_checkbt , FALSE , FALSE , 2 );
   gtk_container_add( GTK_CONTAINER(settings_frame) , settings_vbox );
   /* attach pointers of options to settings_vbox so we can handle all of them in a single callback */
   g_object_set_data( G_OBJECT(settings_vbox) , "ap_opts_length_precalc" , settings_precalc_checkbt );
-  g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+  g_object_set_data( G_OBJECT(settings_vbox) , "ap_opts_comments_extract" , settings_extractcomm_checkbt );
+  g_object_set_data( G_OBJECT(settings_vbox) , "ap_opts_lyrics_extract" , settings_extractlyr_checkbt );
+  g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                             G_CALLBACK(i_configure_ev_settings_commit) , settings_vbox );
 
   gtk_box_pack_start( GTK_BOX(content_vbox) , backend_lv_frame , TRUE , TRUE , 0 );
@@ -256,6 +282,16 @@
                         "Disable this option if you want faster playlist loading (when a lot "
                         "of MIDI files are added), enable it to display more information "
                         "in the playlist straight after loading.") , "" );
+  gtk_tooltips_set_tip( GTK_TOOLTIPS(tips) , settings_extractcomm_checkbt ,
+                        _("* Extract comments from MIDI files *\n"
+                        "Some MIDI files contain text comments (author, copyright, instrument notes, "
+                        "etc.). If this option is enabled, AMIDI-Plug will extract and display comments "
+                        "(if available) in the file information dialog.") , "" );
+  gtk_tooltips_set_tip( GTK_TOOLTIPS(tips) , settings_extractlyr_checkbt ,
+                        _("* Extract lyrics from MIDI files *\n"
+                        "Some MIDI files contain song lyrics. If this option is enabled, AMIDI-Plug "
+                        "will extract and display song lyrics (if available) in the file "
+                        "information dialog.") , "" );
 }
 
 
--- a/Plugins/Input/amidi-plug/i_configure-dummy.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure-dummy.c	Tue Sep 12 10:59:59 2006 -0700
@@ -310,15 +310,15 @@
     }
 
     /* commit events */
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_enablelog_commit) , midilogger_enablelog_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_lfstyle_commit) , midilogger_logfile_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_plspeed_commit) , plspeed_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_logfname_commit) , midilogger_logfile_logfname_entry );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_logdir_commit) , midilogger_logfile_logdir_entry );
 
   }
--- a/Plugins/Input/amidi-plug/i_configure-fluidsynth.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure-fluidsynth.c	Tue Sep 12 10:59:59 2006 -0700
@@ -22,6 +22,15 @@
 #include "i_configure-fluidsynth.h"
 #include "backend-fluidsynth/b-fluidsynth-config.h"
 #include "backend-fluidsynth/backend-fluidsynth-icon.xpm"
+#include <glib/gstdio.h>
+
+
+enum
+{
+  LISTSFONT_FILENAME_COLUMN = 0,
+  LISTSFONT_FILESIZE_COLUMN,
+  LISTSFONT_N_COLUMNS
+};
 
 
 void i_configure_ev_toggle_default( GtkToggleButton *togglebutton , gpointer hbox )
@@ -64,11 +73,116 @@
 }
 
 
-void i_configure_ev_sffile_commit( gpointer sffile_entry )
+void i_configure_ev_sflist_add( gpointer sfont_lv )
+{
+  GtkWidget *parent_window = gtk_widget_get_toplevel( sfont_lv );
+  if ( GTK_WIDGET_TOPLEVEL(parent_window) )
+  {
+    GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(sfont_lv) );
+    GtkTreeIter itersel, iterapp;
+    GtkWidget *browse_dialog = gtk_file_chooser_dialog_new( _("AMIDI-Plug - select SoundFont file") ,
+                                                            GTK_WINDOW(parent_window) ,
+                                                            GTK_FILE_CHOOSER_ACTION_OPEN ,
+                                                            GTK_STOCK_CANCEL , GTK_RESPONSE_CANCEL ,
+                                                            GTK_STOCK_OPEN , GTK_RESPONSE_ACCEPT , NULL );
+    if ( gtk_tree_selection_get_selected( listsel , NULL , &itersel ) )
+    {
+      gchar *selfilename = NULL, *selfiledir = NULL;
+      GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(sfont_lv) );
+      gtk_tree_model_get( GTK_TREE_MODEL(store) , &itersel , LISTSFONT_FILENAME_COLUMN , &selfilename , -1 );
+      selfiledir = g_path_get_dirname( selfilename );
+      gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(browse_dialog) , selfiledir );
+      g_free( selfiledir ); g_free( selfilename );
+    }
+    if ( gtk_dialog_run(GTK_DIALOG(browse_dialog)) == GTK_RESPONSE_ACCEPT )
+    {
+      struct stat finfo;
+      GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(sfont_lv) );
+      gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(browse_dialog) );
+      gint filesize = -1;
+      if ( g_stat( filename , &finfo ) == 0 )
+        filesize = finfo.st_size;
+      gtk_list_store_append( GTK_LIST_STORE(store) , &iterapp );
+      gtk_list_store_set( GTK_LIST_STORE(store) , &iterapp ,
+                          LISTSFONT_FILENAME_COLUMN , filename ,
+                          LISTSFONT_FILESIZE_COLUMN , filesize , -1 );
+      DEBUGMSG( "selected file: %s\n" , filename );
+      g_free( filename );
+    }
+    gtk_widget_destroy( browse_dialog );
+  }
+}
+
+
+void i_configure_ev_sflist_rem( gpointer sfont_lv )
+{
+  GtkTreeModel *store;
+  GtkTreeIter iter;
+  GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(sfont_lv) );
+  if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) )
+    gtk_list_store_remove( GTK_LIST_STORE(store) , &iter );
+}
+
+
+void i_configure_ev_sflist_swap( GtkWidget * button , gpointer sfont_lv )
+{
+  GtkTreeModel *store;
+  GtkTreeIter iter;
+  GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(sfont_lv) );
+
+  if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) )
+  {
+    guint swapdire = GPOINTER_TO_UINT(g_object_get_data( G_OBJECT(button) , "swapdire" ));
+    if ( swapdire == 0 ) /* move up */
+    {
+      GtkTreePath *treepath = gtk_tree_model_get_path( store, &iter );
+      if ( gtk_tree_path_prev( treepath ) )
+      {
+         GtkTreeIter iter_prev;
+         if ( gtk_tree_model_get_iter( store , &iter_prev , treepath ) )
+           gtk_list_store_swap( GTK_LIST_STORE(store) , &iter , &iter_prev );
+      }
+      gtk_tree_path_free( treepath );
+    }
+    else /* move down */
+    {
+      GtkTreeIter iter_prev = iter;
+      if ( gtk_tree_model_iter_next( store , &iter ) )
+        gtk_list_store_swap( GTK_LIST_STORE(store) , &iter , &iter_prev );
+    }
+  }
+}
+
+
+void i_configure_ev_sflist_commit( gpointer sfont_lv )
 {
   amidiplug_cfg_fsyn_t * fsyncfg = amidiplug_cfg_backend->fsyn;
+  GtkTreeIter iter;
+  GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(sfont_lv) );
+  GString *sflist_string = g_string_new( "" );
+
+  if ( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store) , &iter ) == TRUE )
+  {
+    gboolean iter_is_valid = FALSE;
+    do
+    {
+      gchar *fname;
+      gtk_tree_model_get( GTK_TREE_MODEL(store) , &iter ,
+                          LISTSFONT_FILENAME_COLUMN , &fname , -1 );
+      g_string_prepend_c( sflist_string , ';' );
+      g_string_prepend( sflist_string , fname );
+      g_free( fname );
+      iter_is_valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(store) , &iter );
+    }
+    while ( iter_is_valid == TRUE );
+  }
+
+  if ( sflist_string->len > 0 )
+    g_string_truncate( sflist_string , sflist_string->len - 1 );
+
   g_free( fsyncfg->fsyn_soundfont_file ); /* free previous */
-  fsyncfg->fsyn_soundfont_file = g_strdup( gtk_entry_get_text(GTK_ENTRY(sffile_entry)) );
+  fsyncfg->fsyn_soundfont_file = g_strdup( sflist_string->str );
+  g_string_free( sflist_string , TRUE );
 }
 
 
@@ -266,8 +380,14 @@
   if ( fsyn_module_ok )
   {
     GtkWidget *soundfont_frame, *soundfont_vbox;
-    GtkWidget *soundfont_file_label, *soundfont_file_entry, *soundfont_file_bbutton, *soundfont_file_hbox;
-    GtkWidget *soundfont_load_hsep, *soundfont_load_vbox, *soundfont_load_option[2];
+    GtkListStore *soundfont_file_store;
+    GtkCellRenderer *soundfont_file_lv_text_rndr;
+    GtkTreeViewColumn *soundfont_file_lv_fname_col, *soundfont_file_lv_fsize_col;
+    GtkWidget *soundfont_file_hbox, *soundfont_file_lv, *soundfont_file_lv_sw, *soundfont_file_lv_frame;
+    GtkTreeSelection *soundfont_file_lv_sel;
+    GtkWidget *soundfont_file_bbox_vbox, *soundfont_file_bbox_addbt, *soundfont_file_bbox_rembt;
+    GtkWidget *soundfont_file_bbox_mvupbt, *soundfont_file_bbox_mvdownbt;
+    GtkWidget *soundfont_load_hsep, *soundfont_load_hbox, *soundfont_load_option[2];
     GtkWidget *synth_frame, *synth_hbox, *synth_leftcol_vbox, *synth_rightcol_vbox;
     GtkWidget *synth_samplerate_frame, *synth_samplerate_vbox, *synth_samplerate_option[4];
     GtkWidget *synth_samplerate_optionhbox, *synth_samplerate_optionentry, *synth_samplerate_optionlabel;
@@ -297,38 +417,102 @@
     soundfont_vbox = gtk_vbox_new( FALSE , 2 );
     gtk_container_set_border_width( GTK_CONTAINER(soundfont_vbox), 4 );
     gtk_container_add( GTK_CONTAINER(soundfont_frame) , soundfont_vbox );
-    /* soundfont settings - file */
+    /* soundfont settings - soundfont files - listview */
+    soundfont_file_store = gtk_list_store_new( LISTSFONT_N_COLUMNS, G_TYPE_STRING , G_TYPE_INT );
+    if ( strlen(fsyncfg->fsyn_soundfont_file) > 0 )
+    {
+      /* fill soundfont list with fsyn_soundfont_file information */
+      gchar **sffiles = g_strsplit( fsyncfg->fsyn_soundfont_file , ";" , 0 );
+      GtkTreeIter iter;
+      gint i = 0;
+      while ( sffiles[i] != NULL )
+      {
+        gint filesize = -1;
+        struct stat finfo;
+        if ( g_stat( sffiles[i] , &finfo ) == 0 )
+          filesize = finfo.st_size;
+        gtk_list_store_prepend( GTK_LIST_STORE(soundfont_file_store) , &iter );
+        gtk_list_store_set( GTK_LIST_STORE(soundfont_file_store) , &iter ,
+                            LISTSFONT_FILENAME_COLUMN , sffiles[i] ,
+                            LISTSFONT_FILESIZE_COLUMN , filesize , -1 );
+        i++;
+      }
+      g_strfreev( sffiles );
+    }
     soundfont_file_hbox = gtk_hbox_new( FALSE , 2 );
-    soundfont_file_label = gtk_label_new( _("SoundFont filename:") );
-    soundfont_file_entry = gtk_entry_new();
-    g_object_set_data( G_OBJECT(soundfont_file_entry) , "fc-act" ,
-                       GINT_TO_POINTER(GTK_FILE_CHOOSER_ACTION_OPEN) );
-    gtk_entry_set_text( GTK_ENTRY(soundfont_file_entry) , fsyncfg->fsyn_soundfont_file );
-    soundfont_file_bbutton = gtk_button_new_with_label( _("browse") );
-    g_signal_connect_swapped( G_OBJECT(soundfont_file_bbutton) , "clicked" ,
-                              G_CALLBACK(i_configure_ev_browse_for_entry) , soundfont_file_entry );
-    gtk_box_pack_start( GTK_BOX(soundfont_file_hbox) , soundfont_file_label , FALSE , FALSE , 0 );
-    gtk_box_pack_start( GTK_BOX(soundfont_file_hbox) , soundfont_file_entry , TRUE , TRUE , 0 );
-    gtk_box_pack_start( GTK_BOX(soundfont_file_hbox) , soundfont_file_bbutton , FALSE , FALSE , 0 );
+    soundfont_file_lv = gtk_tree_view_new_with_model( GTK_TREE_MODEL(soundfont_file_store) );
+    gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(soundfont_file_lv), TRUE );
+    g_object_unref( soundfont_file_store );
+    soundfont_file_lv_text_rndr = gtk_cell_renderer_text_new();
+    soundfont_file_lv_fname_col = gtk_tree_view_column_new_with_attributes(
+                                    _("Filename") , soundfont_file_lv_text_rndr , "text" ,
+                                    LISTSFONT_FILENAME_COLUMN, NULL );
+    gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(soundfont_file_lv_fname_col) , TRUE );
+    soundfont_file_lv_fsize_col = gtk_tree_view_column_new_with_attributes(
+                                    _("Size (bytes)") , soundfont_file_lv_text_rndr , "text" ,
+                                    LISTSFONT_FILESIZE_COLUMN, NULL );
+    gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(soundfont_file_lv_fsize_col) , FALSE );
+    gtk_tree_view_append_column( GTK_TREE_VIEW(soundfont_file_lv), soundfont_file_lv_fname_col );
+    gtk_tree_view_append_column( GTK_TREE_VIEW(soundfont_file_lv), soundfont_file_lv_fsize_col );
+    soundfont_file_lv_sel = gtk_tree_view_get_selection( GTK_TREE_VIEW(soundfont_file_lv) );
+    gtk_tree_selection_set_mode( GTK_TREE_SELECTION(soundfont_file_lv_sel) , GTK_SELECTION_SINGLE );
+    soundfont_file_lv_sw = gtk_scrolled_window_new( NULL , NULL );
+    gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(soundfont_file_lv_sw) ,
+                                    GTK_POLICY_NEVER , GTK_POLICY_ALWAYS );
+    soundfont_file_lv_frame = gtk_frame_new( NULL );
+    gtk_container_add( GTK_CONTAINER(soundfont_file_lv_sw) , soundfont_file_lv );
+    gtk_container_add( GTK_CONTAINER(soundfont_file_lv_frame) , soundfont_file_lv_sw );
+    /* soundfont settings - soundfont files - buttonbox */
+    soundfont_file_bbox_vbox = gtk_vbox_new( TRUE , 0 );
+    soundfont_file_bbox_addbt = gtk_button_new();
+    gtk_button_set_image( GTK_BUTTON(soundfont_file_bbox_addbt) ,
+                          gtk_image_new_from_stock( GTK_STOCK_ADD , GTK_ICON_SIZE_MENU ) );
+    g_signal_connect_swapped( G_OBJECT(soundfont_file_bbox_addbt) , "clicked" ,
+                              G_CALLBACK(i_configure_ev_sflist_add) , soundfont_file_lv );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_bbox_vbox) , soundfont_file_bbox_addbt , FALSE , FALSE , 0 );
+    soundfont_file_bbox_rembt = gtk_button_new();
+    gtk_button_set_image( GTK_BUTTON(soundfont_file_bbox_rembt) ,
+                          gtk_image_new_from_stock( GTK_STOCK_REMOVE , GTK_ICON_SIZE_MENU ) );
+    g_signal_connect_swapped( G_OBJECT(soundfont_file_bbox_rembt) , "clicked" ,
+                              G_CALLBACK(i_configure_ev_sflist_rem) , soundfont_file_lv );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_bbox_vbox) , soundfont_file_bbox_rembt , FALSE , FALSE , 0 );
+    soundfont_file_bbox_mvupbt = gtk_button_new();
+    gtk_button_set_image( GTK_BUTTON(soundfont_file_bbox_mvupbt) ,
+                          gtk_image_new_from_stock( GTK_STOCK_GO_UP , GTK_ICON_SIZE_MENU ) );
+    g_object_set_data( G_OBJECT(soundfont_file_bbox_mvupbt) , "swapdire" , GUINT_TO_POINTER(0) );
+    g_signal_connect( G_OBJECT(soundfont_file_bbox_mvupbt) , "clicked" ,
+                      G_CALLBACK(i_configure_ev_sflist_swap) , soundfont_file_lv );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_bbox_vbox) , soundfont_file_bbox_mvupbt , FALSE , FALSE , 0 );
+    soundfont_file_bbox_mvdownbt = gtk_button_new();
+    gtk_button_set_image( GTK_BUTTON(soundfont_file_bbox_mvdownbt) ,
+                          gtk_image_new_from_stock( GTK_STOCK_GO_DOWN , GTK_ICON_SIZE_MENU ) );
+    g_object_set_data( G_OBJECT(soundfont_file_bbox_mvdownbt) , "swapdire" , GUINT_TO_POINTER(1) );
+    g_signal_connect( G_OBJECT(soundfont_file_bbox_mvdownbt) , "clicked" ,
+                      G_CALLBACK(i_configure_ev_sflist_swap) , soundfont_file_lv );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_bbox_vbox) , soundfont_file_bbox_mvdownbt , FALSE , FALSE , 0 );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_hbox) , soundfont_file_lv_frame , TRUE , TRUE , 0 );
+    gtk_box_pack_start( GTK_BOX(soundfont_file_hbox) , soundfont_file_bbox_vbox , FALSE , FALSE , 0 );
     gtk_box_pack_start( GTK_BOX(soundfont_vbox) , soundfont_file_hbox , FALSE , FALSE , 0 );
+
     /* soundfont settings - load */
     soundfont_load_hsep = gtk_hseparator_new();
-    soundfont_load_vbox = gtk_vbox_new( FALSE , 0 );
+    soundfont_load_hbox = gtk_hbox_new( FALSE , 0 );
     soundfont_load_option[0] = gtk_radio_button_new_with_label( NULL ,
-                                 _("Load SoundFont on player start") );
+                                 _("Load SF on player start") );
     g_object_set_data( G_OBJECT(soundfont_load_option[0]) , "val" , GINT_TO_POINTER(0) );
     soundfont_load_option[1] = gtk_radio_button_new_with_label_from_widget(
                                  GTK_RADIO_BUTTON(soundfont_load_option[0]) ,
-                                 _("Load SoundFont on first midifile play") );
+                                 _("Load SF on first midifile play") );
     g_object_set_data( G_OBJECT(soundfont_load_option[1]) , "val" , GINT_TO_POINTER(1) );
     if ( fsyncfg->fsyn_soundfont_load == 0 )
       gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(soundfont_load_option[0]) , TRUE );
     else
       gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(soundfont_load_option[1]) , TRUE );
-    gtk_box_pack_start( GTK_BOX(soundfont_load_vbox) , soundfont_load_option[0] , FALSE , FALSE , 0 );
-    gtk_box_pack_start( GTK_BOX(soundfont_load_vbox) , soundfont_load_option[1] , FALSE , FALSE , 0 );
+    gtk_box_pack_start( GTK_BOX(soundfont_load_hbox) , soundfont_load_option[0] , TRUE , TRUE , 0 );
+    gtk_box_pack_start( GTK_BOX(soundfont_load_hbox) , gtk_vseparator_new() , FALSE , FALSE , 4 );
+    gtk_box_pack_start( GTK_BOX(soundfont_load_hbox) , soundfont_load_option[1] , TRUE , TRUE , 0 );
     gtk_box_pack_start( GTK_BOX(soundfont_vbox) , soundfont_load_hsep , FALSE , FALSE , 3 );
-    gtk_box_pack_start( GTK_BOX(soundfont_vbox) , soundfont_load_vbox , FALSE , FALSE , 0 );
+    gtk_box_pack_start( GTK_BOX(soundfont_vbox) , soundfont_load_hbox , FALSE , FALSE , 0 );
 
     gtk_box_pack_start( GTK_BOX(content_vbox) , soundfont_frame , FALSE , FALSE , 0 );
 
@@ -597,32 +781,33 @@
 
     gtk_box_pack_start( GTK_BOX(content_vbox) , buffer_frame , FALSE , FALSE , 0 );
 
-    /* commit events */
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
-                              G_CALLBACK(i_configure_ev_sffile_commit) , soundfont_file_entry );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    /* commit events  */
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
+                              G_CALLBACK(i_configure_ev_sflist_commit) , soundfont_file_lv );
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_sfload_commit) , soundfont_load_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_sygain_commit) , synth_gain_value_spin );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_sypoly_commit) , synth_poly_value_spin );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_syreverb_commit) , synth_reverb_value_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_sychorus_commit) , synth_chorus_value_option[0] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_sysamplerate_commit) , synth_samplerate_option[3] );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_bufsize_commit) , buffer_bufsize_spin );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_bufmarginsize_commit) , buffer_marginsize_spin );
-    g_signal_connect_swapped( G_OBJECT(commit_button) , "clicked" ,
+    g_signal_connect_swapped( G_OBJECT(commit_button) , "ap-commit" ,
                               G_CALLBACK(i_configure_ev_bufmargininc_commit) , buffer_margininc_spin );
 
-    gtk_tooltips_set_tip( GTK_TOOLTIPS(tips) , soundfont_file_entry ,
-                          _("* Select SoundFont *\n"
-                          "In order to play MIDI with FluidSynth, you need to specify a "
-                          "valid SoundFont file here (use absolute paths).") , "" );
+    gtk_tooltips_set_tip( GTK_TOOLTIPS(tips) , soundfont_file_lv ,
+                          _("* Select SoundFont files *\n"
+                          "In order to play MIDI with FluidSynth, you need to specify at "
+                          "least one valid SoundFont file here (use absolute paths). The " 
+                          "loading order is from the top (first) to the bottom (last).") , "" );
     gtk_tooltips_set_tip( GTK_TOOLTIPS(tips) , soundfont_load_option[0] ,
                           _("* Load SoundFont on player start *\n"
                           "Depending on your system speed, SoundFont loading in FluidSynth will "
--- a/Plugins/Input/amidi-plug/i_configure.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure.c	Tue Sep 12 10:59:59 2006 -0700
@@ -34,7 +34,9 @@
 
 
 void i_configure_ev_bcancel( gpointer );
-void i_configure_ev_bok( gpointer );
+void i_configure_ev_bapply( GtkWidget * , gpointer );
+void i_configure_ev_bokcheck( GtkWidget * , gpointer );
+void i_configure_ev_bok( GtkWidget * , gpointer );
 void i_configure_cfg_backend_alloc( void );
 void i_configure_cfg_backend_free( void );
 void i_configure_cfg_backend_save( void );
@@ -92,7 +94,7 @@
   static GtkWidget *configwin = NULL;
   GdkGeometry cw_hints;
   GtkWidget *configwin_vbox;
-  GtkWidget *hseparator, *hbuttonbox, *button_ok, *button_cancel;
+  GtkWidget *hseparator, *hbuttonbox, *button_ok, *button_cancel, *button_apply;
 
   GtkWidget *configwin_notebook;
 
@@ -120,6 +122,14 @@
   g_signal_connect( G_OBJECT(configwin) , "destroy" ,
                     G_CALLBACK(gtk_widget_destroyed) , &configwin );
   button_ok = gtk_button_new_from_stock( GTK_STOCK_OK );
+  if ( g_signal_lookup( "ap-commit" , GTK_WIDGET_TYPE(button_ok) ) == 0 )
+  {
+    g_signal_new( "ap-commit" , GTK_WIDGET_TYPE(button_ok) ,
+                  G_SIGNAL_ACTION , 0 , NULL , NULL ,
+                  g_cclosure_marshal_VOID__VOID , G_TYPE_NONE , 0 );
+  }
+  g_signal_connect( G_OBJECT(button_ok) , "clicked" ,
+                    G_CALLBACK(i_configure_ev_bokcheck) , configwin );
   cw_hints.min_width = 480; cw_hints.min_height = -1;
   gtk_window_set_geometry_hints( GTK_WINDOW(configwin) , GTK_WIDGET(configwin) ,
                                  &cw_hints , GDK_HINT_MIN_SIZE );
@@ -178,13 +188,19 @@
   gtk_box_pack_start( GTK_BOX(configwin_vbox) , hseparator , FALSE , FALSE , 4 );
   hbuttonbox = gtk_hbutton_box_new();
   gtk_button_box_set_layout( GTK_BUTTON_BOX(hbuttonbox) , GTK_BUTTONBOX_END );
+  button_apply = gtk_button_new_from_stock( GTK_STOCK_APPLY );
+  gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_apply );
   button_cancel = gtk_button_new_from_stock( GTK_STOCK_CANCEL );
   g_signal_connect_swapped( G_OBJECT(button_cancel) , "clicked" ,
                             G_CALLBACK(i_configure_ev_bcancel) , configwin );
   gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_cancel );
   /* button_ok = gtk_button_new_from_stock( GTK_STOCK_OK ); created above */
-  g_signal_connect_swapped( G_OBJECT(button_ok) , "clicked" ,
-                            G_CALLBACK(i_configure_ev_bok) , configwin );
+  g_object_set_data( G_OBJECT(button_ok) , "bapply_pressed" , GUINT_TO_POINTER(0) );
+  g_object_set_data( G_OBJECT(button_apply) , "bok" , button_ok );
+  g_signal_connect( G_OBJECT(button_ok) , "ap-commit" ,
+                    G_CALLBACK(i_configure_ev_bok) , configwin );
+  g_signal_connect( G_OBJECT(button_apply) , "clicked" ,
+                    G_CALLBACK(i_configure_ev_bapply) , configwin );
   gtk_container_add( GTK_CONTAINER(hbuttonbox) , button_ok );
   gtk_box_pack_start( GTK_BOX(configwin_vbox) , hbuttonbox , FALSE , FALSE , 0 );
 
@@ -194,17 +210,26 @@
 
 void i_configure_ev_bcancel( gpointer configwin )
 {
-  i_configure_cfg_backend_free();
+  i_configure_cfg_backend_free(); /* free backend settings */
   gtk_widget_destroy(GTK_WIDGET(configwin));
 }
 
 
-void i_configure_ev_bok( gpointer configwin )
+void i_configure_ev_bapply( GtkWidget * button_apply , gpointer configwin )
+{
+  GtkWidget *button_ok = g_object_get_data( G_OBJECT(button_apply) , "bok" );
+  g_object_set_data( G_OBJECT(button_ok) , "bapply_pressed" , GUINT_TO_POINTER(1) );
+  i_configure_ev_bokcheck( button_ok , configwin );
+}
+
+
+void i_configure_ev_bokcheck( GtkWidget * button_ok , gpointer configwin )
 {
   if ( xmms_remote_is_playing(0) || xmms_remote_is_paused(0) )
   {
     /* we can't change settings while a song is being played */
     static GtkWidget * configwin_warnmsg = NULL;
+    g_object_set_data( G_OBJECT(button_ok) , "bapply_pressed" , GUINT_TO_POINTER(0) );
     if ( configwin_warnmsg != NULL )
     {
       gdk_window_raise( configwin_warnmsg->window );
@@ -213,7 +238,7 @@
     {
       configwin_warnmsg = (GtkWidget*)i_message_gui( _("AMIDI-Plug message") ,
                                         _("Please stop the player before changing AMIDI-Plug settings.") ,
-                                        AMIDIPLUG_MESSAGE_WARN , configwin );
+                                        AMIDIPLUG_MESSAGE_WARN , configwin , FALSE );
       g_signal_connect( G_OBJECT(configwin_warnmsg) , "destroy" ,
                         G_CALLBACK(gtk_widget_destroyed) , &configwin_warnmsg );
       gtk_widget_show_all( configwin_warnmsg );
@@ -221,26 +246,42 @@
   }
   else
   {
-    DEBUGMSG( "saving configuration...\n" );
-    i_configure_cfg_ap_save(); /* save amidiplug settings */
-    i_configure_cfg_backend_save(); /* save backend settings */
-    i_configure_cfg_backend_free(); /* free backend settings */
-    DEBUGMSG( "configuration saved\n" );
+    g_signal_emit_by_name( G_OBJECT(button_ok) , "ap-commit" ); /* call commit actions */
+  }
+}
+
 
-    /* check if a different backend has been selected */
-    if ( strcmp( amidiplug_cfg_ap.ap_seq_backend , backend.name ) )
-    {
-      DEBUGMSG( "a new backend has been selected, unloading previous and loading the new one\n" );
-      i_backend_unload(); /* unload previous backend */
-      i_backend_load( amidiplug_cfg_ap.ap_seq_backend ); /* load new backend */
-    }
-    else /* same backend, just reload updated configuration */
+void i_configure_ev_bok( GtkWidget * button_ok , gpointer configwin )
+{
+  DEBUGMSG( "saving configuration...\n" );
+  i_configure_cfg_ap_save(); /* save amidiplug settings */
+  i_configure_cfg_backend_save(); /* save backend settings */
+  DEBUGMSG( "configuration saved\n" );
+
+  /* check if a different backend has been selected */
+  if (( backend.name == NULL ) || ( strcmp( amidiplug_cfg_ap.ap_seq_backend , backend.name ) ))
+  {
+    DEBUGMSG( "a new backend has been selected, unloading previous and loading the new one\n" );
+    i_backend_unload(); /* unload previous backend */
+    i_backend_load( amidiplug_cfg_ap.ap_seq_backend ); /* load new backend */
+  }
+  else /* same backend, just reload updated configuration */
+  {
+    if ( backend.gmodule != NULL )
     {
       DEBUGMSG( "the selected backend is already loaded, so just perform backend cleanup and reinit\n" );
       backend.cleanup();
       backend.init();
     }
+  }
 
+  if ( GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(button_ok),"bapply_pressed")) == 1 )
+  {
+    g_object_set_data( G_OBJECT(button_ok) , "bapply_pressed" , GUINT_TO_POINTER(0) );
+  }
+  else
+  {
+    i_configure_cfg_backend_free(); /* free backend settings */
     gtk_widget_destroy(GTK_WIDGET(configwin));
   }
 }
@@ -318,6 +359,8 @@
     /* amidi-plug defaults */
     amidiplug_cfg_ap.ap_seq_backend = g_strdup( "alsa" );
     amidiplug_cfg_ap.ap_opts_length_precalc = 0;
+    amidiplug_cfg_ap.ap_opts_lyrics_extract = 0;
+    amidiplug_cfg_ap.ap_opts_comments_extract = 0;
   }
   else
   {
@@ -325,6 +368,10 @@
                         &amidiplug_cfg_ap.ap_seq_backend , "alsa" );
     i_pcfg_read_integer( cfgfile , "general" , "ap_opts_length_precalc" ,
                          &amidiplug_cfg_ap.ap_opts_length_precalc , 0 );
+    i_pcfg_read_integer( cfgfile , "general" , "ap_opts_lyrics_extract" ,
+                         &amidiplug_cfg_ap.ap_opts_lyrics_extract , 0 );
+    i_pcfg_read_integer( cfgfile , "general" , "ap_opts_comments_extract" ,
+                         &amidiplug_cfg_ap.ap_opts_comments_extract , 0 );
     i_pcfg_free( cfgfile );
   }
 
@@ -343,8 +390,14 @@
     cfgfile = i_pcfg_new();
 
   /* save amidi-plug config information */
-  i_pcfg_write_string( cfgfile , "general" , "ap_seq_backend" , amidiplug_cfg_ap.ap_seq_backend );
-  i_pcfg_write_integer( cfgfile , "general" , "ap_opts_length_precalc" , amidiplug_cfg_ap.ap_opts_length_precalc );
+  i_pcfg_write_string( cfgfile , "general" , "ap_seq_backend" ,
+                       amidiplug_cfg_ap.ap_seq_backend );
+  i_pcfg_write_integer( cfgfile , "general" , "ap_opts_length_precalc" ,
+                        amidiplug_cfg_ap.ap_opts_length_precalc );
+  i_pcfg_write_integer( cfgfile , "general" , "ap_opts_lyrics_extract" ,
+                        amidiplug_cfg_ap.ap_opts_lyrics_extract );
+  i_pcfg_write_integer( cfgfile , "general" , "ap_opts_comments_extract" ,
+                        amidiplug_cfg_ap.ap_opts_comments_extract );
 
   i_pcfg_write_to_file( cfgfile , config_pathfilename );
   i_pcfg_free( cfgfile );
--- a/Plugins/Input/amidi-plug/i_configure.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_configure.h	Tue Sep 12 10:59:59 2006 -0700
@@ -28,6 +28,8 @@
 {
   gchar *	ap_seq_backend;
   gint		ap_opts_length_precalc;
+  gint		ap_opts_comments_extract;
+  gint		ap_opts_lyrics_extract;
 }
 amidiplug_cfg_ap_t;
 
--- a/Plugins/Input/amidi-plug/i_fileinfo.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_fileinfo.c	Tue Sep 12 10:59:59 2006 -0700
@@ -21,6 +21,7 @@
 
 #include <gtk/gtk.h>
 #include "i_fileinfo.h"
+#include "i_configure.h"
 /* this is needed to retrieve information */
 #include "i_midi.h"
 /* icon from gnome-mime-audio-midi.png of the GNOME ICON SET */
@@ -59,12 +60,62 @@
 }
 
 
+/* COMMENT: this will also reset current position in each track! */
+void i_fileinfo_text_fill( midifile_t * mf , GtkTextBuffer * text_tb, GtkTextBuffer * lyrics_tb )
+{
+  gint l = 0;
+  /* initialize current position in each track */
+  for (l = 0; l < mf->num_tracks; ++l)
+    mf->tracks[l].current_event = mf->tracks[l].first_event;
+
+  for (;;)
+  {
+    midievent_t * event = NULL;
+    midifile_track_t * event_track = NULL;
+    gint i, min_tick = mf->max_tick + 1;
+
+    /* search next event */
+    for ( i = 0 ; i < mf->num_tracks ; ++i )
+    {
+      midifile_track_t * track = &mf->tracks[i];
+      midievent_t * e2 = track->current_event;
+      if (( e2 ) && ( e2->tick < min_tick ))
+      {
+        min_tick = e2->tick;
+        event = e2;
+        event_track = track;
+      }
+    }
+
+    if (!event)
+      break; /* end of song reached */
+
+    /* advance pointer to next event */
+    event_track->current_event = event->next;
+
+    switch ( event->type )
+    {
+      case SND_SEQ_EVENT_META_TEXT:
+        gtk_text_buffer_insert_at_cursor( text_tb , event->data.metat , strlen(event->data.metat) );
+        break;
+      case SND_SEQ_EVENT_META_LYRIC:
+        gtk_text_buffer_insert_at_cursor( lyrics_tb , event->data.metat , strlen(event->data.metat) );
+        break;
+    }
+  }
+}
+
+
 void i_fileinfo_gui( gchar * filename )
 {
   static GtkWidget *fileinfowin = NULL;
-  GtkWidget *fileinfowin_vbox;
-  GtkWidget *title_hbox , *title_icon_image , *title_name_f_label , *title_name_v_entry;
-  GtkWidget *info_frame , *info_table;
+  GtkWidget *fileinfowin_vbox, *fileinfowin_columns_hbox;
+  GtkWidget *midiinfoboxes_vbox, *miditextboxes_vbox, *miditextboxes_paned;
+  GtkWidget *title_hbox, *title_icon_image, *title_name_f_label, *title_name_v_entry;
+  GtkWidget *info_frame, *info_frame_tl, *info_table;
+  GtkWidget *text_frame, *text_frame_tl, *text_tv, *text_tv_sw;
+  GtkWidget *lyrics_frame, *lyrics_tv, *lyrics_tv_sw;
+  GtkTextBuffer *text_tb, *lyrics_tb;
   GtkWidget *footer_hbbox, *footer_bclose;
   GdkPixbuf *title_icon_pixbuf;
   PangoAttrList *pangoattrlist;
@@ -89,7 +140,6 @@
 
   fileinfowin = gtk_window_new( GTK_WINDOW_TOPLEVEL );
   gtk_window_set_type_hint( GTK_WINDOW(fileinfowin), GDK_WINDOW_TYPE_HINT_DIALOG );
-  gtk_window_set_resizable( GTK_WINDOW(fileinfowin) , FALSE );
   gtk_window_set_position( GTK_WINDOW(fileinfowin) , GTK_WIN_POS_CENTER );
   g_signal_connect( G_OBJECT(fileinfowin) , "destroy" , G_CALLBACK(i_fileinfo_ev_destroy) , mf );
   g_signal_connect( G_OBJECT(fileinfowin) , "destroy" , G_CALLBACK(gtk_widget_destroyed) , &fileinfowin );
@@ -125,10 +175,26 @@
   gtk_widget_set_size_request( GTK_WIDGET(title_name_v_entry) , 200 , -1 );
   gtk_box_pack_start(GTK_BOX(title_hbox) , title_name_v_entry , TRUE , TRUE , 0 );
 
+  fileinfowin_columns_hbox = gtk_hbox_new( FALSE , 2 );
+  gtk_box_pack_start( GTK_BOX(fileinfowin_vbox) , fileinfowin_columns_hbox , TRUE , TRUE , 0 );
+
   /*********************
    *** MIDI INFO BOX ***/
-  info_frame = gtk_frame_new( _(" MIDI Info ") );
-  gtk_box_pack_start( GTK_BOX(fileinfowin_vbox) , info_frame , TRUE , TRUE , 0 );
+  midiinfoboxes_vbox = gtk_vbox_new( FALSE , 2 );
+  /* pick the entire space if both comments and lyrics boxes are not displayed,
+     pick only required space if at least one of them is displayed */
+  if (( amidiplug_cfg_ap.ap_opts_comments_extract == 0 ) &&
+      ( amidiplug_cfg_ap.ap_opts_lyrics_extract == 0 ))
+    gtk_box_pack_start( GTK_BOX(fileinfowin_columns_hbox) , midiinfoboxes_vbox , TRUE , TRUE , 0 );
+  else
+    gtk_box_pack_start( GTK_BOX(fileinfowin_columns_hbox) , midiinfoboxes_vbox , FALSE , FALSE , 0 );
+
+  info_frame_tl = gtk_label_new( "" );
+  gtk_label_set_markup( GTK_LABEL(info_frame_tl) , _("<span size=\"smaller\"> MIDI Info </span>") );
+  gtk_box_pack_start( GTK_BOX(midiinfoboxes_vbox) , info_frame_tl , FALSE , FALSE , 0 );
+
+  info_frame = gtk_frame_new( NULL );
+  gtk_box_pack_start( GTK_BOX(midiinfoboxes_vbox) , info_frame , TRUE , TRUE , 0 );
   info_table = gtk_table_new( 6 , 2 , FALSE );
   gtk_container_set_border_width( GTK_CONTAINER(info_table) , 5 );
   gtk_container_add( GTK_CONTAINER(info_frame) , info_table );
@@ -161,6 +227,101 @@
 
   g_string_free( value_gstring , TRUE );
 
+  /**********************************
+   *** MIDI COMMENTS/LYRICS BOXES ***/
+  miditextboxes_vbox = gtk_vbox_new( FALSE , 2 );
+  gtk_box_pack_start( GTK_BOX(fileinfowin_columns_hbox) , miditextboxes_vbox , TRUE , TRUE , 0 );
+
+  text_frame_tl = gtk_label_new( "" );
+  gtk_label_set_markup( GTK_LABEL(text_frame_tl) ,
+                        _("<span size=\"smaller\"> MIDI Comments and Lyrics </span>") );
+  gtk_box_pack_start( GTK_BOX(miditextboxes_vbox) , text_frame_tl , FALSE , FALSE , 0 );
+
+  miditextboxes_paned = gtk_vpaned_new();
+  gtk_box_pack_start( GTK_BOX(miditextboxes_vbox) , miditextboxes_paned , TRUE , TRUE , 0 );
+
+  text_frame = gtk_frame_new( NULL );
+  gtk_paned_pack1( GTK_PANED(miditextboxes_paned) , text_frame , TRUE , TRUE );
+  text_tv = gtk_text_view_new();
+  gtk_text_view_set_editable( GTK_TEXT_VIEW(text_tv) , FALSE );
+  gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(text_tv) , FALSE );
+  gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(text_tv) , GTK_WRAP_WORD );
+  gtk_text_view_set_right_margin( GTK_TEXT_VIEW(text_tv) , 4 );
+  gtk_text_view_set_left_margin( GTK_TEXT_VIEW(text_tv) , 4 );
+  gtk_widget_set_size_request( text_tv , 300 , 113 );
+  text_tv_sw = gtk_scrolled_window_new( NULL , NULL );
+  gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(text_tv_sw) ,
+                                  GTK_POLICY_AUTOMATIC , GTK_POLICY_ALWAYS );
+  gtk_container_add( GTK_CONTAINER(text_frame) , text_tv_sw );
+  gtk_container_add( GTK_CONTAINER(text_tv_sw) , text_tv );
+
+  lyrics_frame = gtk_frame_new( NULL );
+  gtk_paned_pack2( GTK_PANED(miditextboxes_paned) , lyrics_frame , TRUE , TRUE );
+  lyrics_tv = gtk_text_view_new();
+  gtk_text_view_set_editable( GTK_TEXT_VIEW(lyrics_tv) , FALSE );
+  gtk_text_view_set_cursor_visible( GTK_TEXT_VIEW(lyrics_tv) , FALSE );
+  gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(lyrics_tv) , GTK_WRAP_WORD );
+  gtk_text_view_set_right_margin( GTK_TEXT_VIEW(lyrics_tv) , 4 );
+  gtk_text_view_set_left_margin( GTK_TEXT_VIEW(lyrics_tv) , 4 );
+  gtk_widget_set_size_request( lyrics_tv , 300 , 113 );
+  lyrics_tv_sw = gtk_scrolled_window_new( NULL , NULL );
+  gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(lyrics_tv_sw) ,
+                                  GTK_POLICY_AUTOMATIC , GTK_POLICY_ALWAYS );
+  gtk_container_add( GTK_CONTAINER(lyrics_frame) , lyrics_tv_sw );
+  gtk_container_add( GTK_CONTAINER(lyrics_tv_sw) , lyrics_tv );
+
+  text_tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(text_tv) );
+  lyrics_tb = gtk_text_view_get_buffer( GTK_TEXT_VIEW(lyrics_tv) );
+
+  /* call the buffer fill routine if at least one between comments and lyrics is enabled */
+  if (( amidiplug_cfg_ap.ap_opts_comments_extract > 0 ) ||
+      ( amidiplug_cfg_ap.ap_opts_lyrics_extract > 0 ))
+    i_fileinfo_text_fill( mf , text_tb , lyrics_tb );
+
+  if (( amidiplug_cfg_ap.ap_opts_comments_extract > 0 ) &&
+      ( gtk_text_buffer_get_char_count( text_tb ) == 0 ))
+  {
+    GtkTextIter start, end;
+    GtkTextTag *tag = gtk_text_buffer_create_tag( text_tb , "italicstyle" ,
+                                                  "style" , PANGO_STYLE_ITALIC , NULL );
+    /*gtk_text_view_set_justification( GTK_TEXT_VIEW(text_tv) , GTK_JUSTIFY_CENTER );*/
+    gtk_text_buffer_set_text( text_tb , _("* no comments available in this MIDI file *") , -1 );
+    gtk_text_buffer_get_iter_at_offset( text_tb , &start , 0 );
+    gtk_text_buffer_get_iter_at_offset( text_tb , &end , -1 );
+    gtk_text_buffer_apply_tag( text_tb , tag , &start , &end );
+  }
+
+  if (( amidiplug_cfg_ap.ap_opts_lyrics_extract > 0 ) &&
+      ( gtk_text_buffer_get_char_count( lyrics_tb ) == 0 ))
+  {
+    GtkTextIter start, end;
+    GtkTextTag *tag = gtk_text_buffer_create_tag( lyrics_tb , "italicstyle" ,
+                                                  "style" , PANGO_STYLE_ITALIC , NULL );
+    /*gtk_text_view_set_justification( GTK_TEXT_VIEW(lyrics_tv) , GTK_JUSTIFY_CENTER );*/
+    gtk_text_buffer_set_text( lyrics_tb , _("* no lyrics available in this MIDI file *") , -1 );
+    gtk_text_buffer_get_iter_at_offset( lyrics_tb , &start , 0 );
+    gtk_text_buffer_get_iter_at_offset( lyrics_tb , &end , -1 );
+    gtk_text_buffer_apply_tag( lyrics_tb , tag , &start , &end );
+  }
+
+  /* hide boxes for disabled options (comments and/or lyrics) */
+  if (( amidiplug_cfg_ap.ap_opts_comments_extract == 0 ) &&
+      ( amidiplug_cfg_ap.ap_opts_lyrics_extract == 0 ))
+  {
+    gtk_widget_set_no_show_all( miditextboxes_vbox , TRUE );
+    gtk_widget_hide( miditextboxes_vbox );
+  }
+  else if ( amidiplug_cfg_ap.ap_opts_comments_extract == 0 )
+  {
+    gtk_widget_set_no_show_all( text_frame , TRUE );
+    gtk_widget_hide( text_frame );
+  }
+  else if ( amidiplug_cfg_ap.ap_opts_lyrics_extract == 0 )
+  {
+    gtk_widget_set_no_show_all( lyrics_frame , TRUE );
+    gtk_widget_hide( lyrics_frame );
+  }
+
   /**************
    *** FOOTER ***/
   footer_hbbox = gtk_hbutton_box_new();
--- a/Plugins/Input/amidi-plug/i_midi.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_midi.c	Tue Sep 12 10:59:59 2006 -0700
@@ -23,6 +23,7 @@
 
 
 #include "i_midi.h"
+#include "i_configure.h"
 
 #define ERRMSG_MIDITRACK() { g_warning( "%s: invalid MIDI data (offset %#x)" , mf->file_name , mf->file_offset ); return 0; }
 
@@ -278,6 +279,46 @@
               }
               break;
 
+              case 0x01: /* text comments */
+              {
+                if ( amidiplug_cfg_ap.ap_opts_comments_extract > 0 )
+                {
+                  gint ic = 0;
+                  if (len < 1)
+                    ERRMSG_MIDITRACK();
+                  event = i_midi_file_new_event(track, 0);
+                  event->type = SND_SEQ_EVENT_META_TEXT;
+                  event->tick = tick;
+                  event->data.metat = calloc( len + 1 , sizeof(gchar) );
+                  for ( ic = 0 ; ic < len ; ic++ )
+                    event->data.metat[ic] = i_midi_file_read_byte(mf);
+                  event->data.metat[len] = '\0';
+                }
+                else
+                  i_midi_file_skip_bytes(mf,len);
+              }
+              break;
+
+              case 0x05: /* lyrics */
+              {
+                if ( amidiplug_cfg_ap.ap_opts_lyrics_extract > 0 )
+                {
+                  gint ic = 0;
+                  if (len < 1)
+                    ERRMSG_MIDITRACK();
+                  event = i_midi_file_new_event(track, 0);
+                  event->type = SND_SEQ_EVENT_META_LYRIC;
+                  event->tick = tick;
+                  event->data.metat = calloc( len + 1 , sizeof(gchar) );
+                  for ( ic = 0 ; ic < len ; ic++ )
+                    event->data.metat[ic] = i_midi_file_read_byte(mf);
+                  event->data.metat[len] = '\0';
+                }
+                else
+                  i_midi_file_skip_bytes(mf,len);
+              }
+              break;
+
               default: /* ignore all other meta events */
               {
                 i_midi_file_skip_bytes(mf,len);
@@ -463,6 +504,9 @@
       {
         event_tmp = event;
         event = event->next;
+        if (( event_tmp->type == SND_SEQ_EVENT_META_TEXT ) ||
+            ( event_tmp->type == SND_SEQ_EVENT_META_LYRIC ))
+          free( event_tmp->data.metat );
         free( event_tmp );
       }
     }
--- a/Plugins/Input/amidi-plug/i_midi.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_midi.h	Tue Sep 12 10:59:59 2006 -0700
@@ -214,6 +214,11 @@
   /* reserved for user apps; event data type = #snd_seq_ev_ext_t */
   SND_SEQ_EVENT_USR_VAR4,
 
+  /* added to support meta-event - general purpose text */
+  SND_SEQ_EVENT_META_TEXT = 150,
+  /* added to support meta-event - lyrics */
+  SND_SEQ_EVENT_META_LYRIC,
+
   /* NOP; ignored in any case */
   SND_SEQ_EVENT_NONE = 255
 };
--- a/Plugins/Input/amidi-plug/i_midievent.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_midievent.h	Tue Sep 12 10:59:59 2006 -0700
@@ -31,6 +31,7 @@
     guchar d[3];			/* channel and data bytes */
     gint tempo;
     guint length;			/* length of sysex data */
+    gchar * metat;			/* meta-event text */
   } data;
   guchar sysex[0];
 };
--- a/Plugins/Input/amidi-plug/i_utils.c	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_utils.c	Tue Sep 12 10:59:59 2006 -0700
@@ -107,7 +107,7 @@
 
 
 gpointer i_message_gui( gchar * title , gchar * message ,
-                        gint type , gpointer parent_win )
+                        gint type , gpointer parent_win , gboolean show_win )
 {
   GtkWidget *win;
   GtkMessageType mtype = GTK_MESSAGE_INFO;
@@ -130,6 +130,9 @@
 
   gtk_window_set_title( GTK_WINDOW(win) , title );
   g_signal_connect_swapped( G_OBJECT(win) , "response" , G_CALLBACK(gtk_widget_destroy) , win );
+ 
+  if ( show_win == TRUE )
+    gtk_widget_show_all( win );
 
   return win;
 }
--- a/Plugins/Input/amidi-plug/i_utils.h	Mon Sep 11 16:06:23 2006 -0700
+++ b/Plugins/Input/amidi-plug/i_utils.h	Tue Sep 12 10:59:59 2006 -0700
@@ -29,6 +29,6 @@
 
 
 void i_about_gui( void );
-gpointer i_message_gui( gchar * , gchar * , gint , gpointer );
+gpointer i_message_gui( gchar * , gchar * , gint , gpointer , gboolean );
 
 #endif /* !_I_UTILS_H */
--- a/configure.ac	Mon Sep 11 16:06:23 2006 -0700
+++ b/configure.ac	Tue Sep 12 10:59:59 2006 -0700
@@ -757,8 +757,8 @@
   INPUT_PLUGINS="$INPUT_PLUGINS amidi-plug"
   PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.6.0],,)
   PKG_CHECK_MODULES(GMODULE, [gmodule-2.0 >= 2.6.0],,)
-  AMIDIPLUGDATADIR=${libdir}/amidi-plug/backends
-  AC_SUBST(AMIDIPLUGDATADIR)
+  AMIDIPLUGBACKENDDIR=${libdir}/amidi-plug/backends
+  AC_SUBST(AMIDIPLUGBACKENDDIR)
   if test "x$enable_amidiplug_alsa" = "xauto" -o "x$enable_amidiplug_alsa" = "xyes"; then
     if test "x$alsalib_available" = "xcheck"; then
       PKG_CHECK_MODULES(ALSA, [alsa >= 1.0],
--- a/mk/rules.mk.in	Mon Sep 11 16:06:23 2006 -0700
+++ b/mk/rules.mk.in	Tue Sep 12 10:59:59 2006 -0700
@@ -62,7 +62,7 @@
 ALSA_LIBS ?= @ALSA_LIBS@
 AMDEP_FALSE ?= @AMDEP_FALSE@
 AMDEP_TRUE ?= @AMDEP_TRUE@
-AMIDIPLUGDATADIR ?= @AMIDIPLUGDATADIR@
+AMIDIPLUGBACKENDDIR ?= @AMIDIPLUGBACKENDDIR@
 AMTAR ?= @AMTAR@
 AR ?= @AR@
 ARCH_DEFINES ?= @ARCH_DEFINES@