changeset 611:3f7a52adfe0e trunk

[svn] merge recent changes from yaz's branch. - stable shoutcast playback. - tag handling improvement. - view track detail on streaming won't crash. (disabled.) - filepopup for streaming is partially supported. filepopup displays track name and stream name, but not updated automatically.
author yaz
date Tue, 06 Feb 2007 12:11:42 -0800
parents 862190d39e00
children 951b24719ce9
files ChangeLog src/madplug/configure.c src/madplug/decoder.c src/madplug/fileinfo.c src/madplug/input.c src/madplug/input.h src/madplug/plugin.c src/madplug/plugin.h src/madplug/replaygain.c
diffstat 9 files changed, 807 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Feb 05 12:28:01 2007 -0800
+++ b/ChangeLog	Tue Feb 06 12:11:42 2007 -0800
@@ -1,3 +1,24 @@
+2007-02-05 20:28:01 +0000  William Pitcock <nenolod@sacredspiral.co.uk>
+  revision [1306]
+  - add madplug. It is not yet hooked up, I'll do that later.
+  
+  trunk/src/madplug/Makefile     |   25 +
+  trunk/src/madplug/configure.c  |  251 ++++++++++
+  trunk/src/madplug/decoder.c    |  567 ++++++++++++++++++++++++
+  trunk/src/madplug/dither.c     |  115 ++++
+  trunk/src/madplug/fileinfo.c   |  644 +++++++++++++++++++++++++++
+  trunk/src/madplug/input.c      |  518 ++++++++++++++++++++++
+  trunk/src/madplug/input.h      |   35 +
+  trunk/src/madplug/mp3.xpm      |  963 +++++++++++++++++++++++++++++++++++++++++
+  trunk/src/madplug/plugin.c     |  568 ++++++++++++++++++++++++
+  trunk/src/madplug/plugin.h     |  131 +++++
+  trunk/src/madplug/replaygain.c |  254 ++++++++++
+  trunk/src/madplug/replaygain.h |   44 +
+  trunk/src/madplug/xing.c       |   91 +++
+  trunk/src/madplug/xing.h       |   48 ++
+  14 files changed, 4254 insertions(+)
+
+
 2007-02-05 00:43:27 +0000  Giacomo Lozito <james@develia.org>
   revision [1304]
   - aosd: avoid collision between playback start trigger and titlechange trigger, that occurred when the next file in playlist was played
--- a/src/madplug/configure.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/configure.c	Tue Feb 06 12:11:42 2007 -0800
@@ -27,7 +27,7 @@
 
 static GtkWidget *configure_win = NULL;
 static GtkWidget *vbox;
-static GtkWidget *fast_playback, *use_xing, *dither;
+static GtkWidget *fast_playback, *use_xing, *dither, *sjis;
 static GtkWidget *RG_enable, *RG_track_mode, *RG_default, *pregain,
     *hard_limit;
 static GtkWidget *title_id3_box, *title_tag_desc;
@@ -47,6 +47,8 @@
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_xing));
     audmad_config.dither =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dither));
+    audmad_config.sjis =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sjis));
 
     audmad_config.replaygain.enable =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(RG_enable));
@@ -69,6 +71,7 @@
                         audmad_config.fast_play_time_calc);
     bmp_cfg_db_set_bool(db, "MAD", "use_xing", audmad_config.use_xing);
     bmp_cfg_db_set_bool(db, "MAD", "dither", audmad_config.dither);
+    bmp_cfg_db_set_bool(db, "MAD", "sjis", audmad_config.sjis);
     bmp_cfg_db_set_bool(db, "MAD", "hard_limit",
                         audmad_config.hard_limit);
     bmp_cfg_db_set_string(db, "MAD", "pregain_db",
@@ -102,6 +105,116 @@
     gtk_widget_set_sensitive(title_tag_desc, override);
 }
 
+#if 0
+// derived from xmms-mad.
+void audmad_configure(void)
+{
+    GtkWidget *bbox, *ok, *cancel;
+    GtkWidget *label, *RG_default_hbox, *pregain_hbox;
+
+    if (configure_win != NULL) {
+        gdk_window_raise(configure_win->window);
+        return;
+    }
+
+    configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
+                       GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                       &configure_win);
+    gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
+                       GTK_SIGNAL_FUNC(configure_destroy), &configure_win);
+    gtk_window_set_title(GTK_WINDOW(configure_win),
+                         "MAD Input Plugin Configuration");
+    gtk_window_set_policy(GTK_WINDOW(configure_win), FALSE, FALSE, FALSE);
+    gtk_container_border_width(GTK_CONTAINER(configure_win), 10);
+
+    vbox = gtk_vbox_new(FALSE, 10);
+    gtk_container_add(GTK_CONTAINER(configure_win), vbox);
+
+    fast_playback =
+        gtk_check_button_new_with_label("Use fast playtime calculation");
+    gtk_box_pack_start(GTK_BOX(vbox), fast_playback, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fast_playback),
+                                 audmad_config.fast_play_time_calc);
+
+    use_xing = gtk_check_button_new_with_label("Parse XING headers");
+    gtk_box_pack_start(GTK_BOX(vbox), use_xing, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_xing),
+                                 audmad_config.use_xing);
+
+    dither =
+        gtk_check_button_new_with_label
+        ("Dither output when rounding to 16-bit");
+    gtk_box_pack_start(GTK_BOX(vbox), dither, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dither),
+                                 audmad_config.dither);
+
+    sjis = gtk_check_button_new_with_label("Use SJIS to write ID3 tags instead of UTF-8");
+    gtk_box_pack_start(GTK_BOX(vbox), sjis, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sjis), audmad_config.sjis);
+
+    /* SKR added config : */
+    RG_enable = gtk_check_button_new_with_label("Enable replaygain");
+    gtk_box_pack_start(GTK_BOX(vbox), RG_enable, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RG_enable),
+                                 audmad_config.replaygain.enable);
+    RG_track_mode =
+        gtk_check_button_new_with_label("Prefer TRACK replaygain");
+    gtk_box_pack_start(GTK_BOX(vbox), RG_track_mode, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RG_track_mode),
+                                 audmad_config.replaygain.track_mode);
+
+    hard_limit =
+        gtk_check_button_new_with_label
+        ("hard-limit samples (prevent clipping)");
+    gtk_box_pack_start(GTK_BOX(vbox), hard_limit, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hard_limit),
+                                 audmad_config.hard_limit);
+
+    label = gtk_label_new("gain to use if no RG tag (dB):");
+    RG_default_hbox = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox), RG_default_hbox, TRUE, TRUE, 0);
+    RG_default = gtk_entry_new();
+    gtk_widget_set_usize(RG_default, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(RG_default),
+                       audmad_config.replaygain.default_db);
+    gtk_box_pack_start(GTK_BOX(RG_default_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(RG_default_hbox), RG_default, FALSE, TRUE,
+                       0);
+
+    label = gtk_label_new("Pre-gain (dB):");
+    pregain_hbox = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox), pregain_hbox, TRUE, TRUE, 0);
+    pregain = gtk_entry_new();
+    gtk_widget_set_usize(pregain, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(pregain), audmad_config.pregain_db);
+    gtk_box_pack_start(GTK_BOX(pregain_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(pregain_hbox), pregain, FALSE, TRUE, 0);
+
+
+    bbox = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+    gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+
+    ok = gtk_button_new_with_label("Ok");
+    gtk_signal_connect(GTK_OBJECT(ok), "clicked",
+                       GTK_SIGNAL_FUNC(configure_win_ok), NULL);
+    GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+    gtk_widget_grab_default(ok);
+
+    cancel = gtk_button_new_with_label("Cancel");
+    gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
+                              GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                              GTK_OBJECT(configure_win));
+    GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+    gtk_widget_show_all(configure_win);
+}
+#endif
+
 void audmad_configure(void)
 {
     GtkWidget *bbox, *ok, *cancel;
@@ -147,6 +260,10 @@
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_xing),
                                  audmad_config.use_xing);
 
+    sjis = gtk_check_button_new_with_label("Use SJIS to write ID3 tags instead of UTF-8");
+    gtk_box_pack_start(GTK_BOX(vbox2), sjis, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sjis), audmad_config.sjis);
+
     dither =
         gtk_check_button_new_with_label
         (_("Dither output when rounding to 16-bit"));
--- a/src/madplug/decoder.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/decoder.c	Tue Feb 06 12:11:42 2007 -0800
@@ -27,6 +27,7 @@
 #include <audacious/plugin.h>
 #include <audacious/output.h>
 #include <audacious/util.h>
+#include <sys/time.h>
 #include "plugin.h"
 #include "input.h"
 
@@ -152,11 +153,11 @@
         }
     }
     assert(pos == olen);
-    if (info->playback->playing == 0)
+    if (!info->playback->playing)
         return;
-    produce_audio(mad_plugin->output->written_time(),
-                  FMT_S16_LE, MAD_NCHANNELS(header), olen, output, NULL);
-    if (info->playback->playing == 0)
+    produce_audio(info->playback->output->written_time(),
+                  FMT_S16_LE, MAD_NCHANNELS(header), olen, output, &(info->playback->playing));
+    if (!info->playback->playing)
         return;
     g_free(output);
 }
@@ -245,11 +246,13 @@
             }
             info->frames++;
 #ifdef DEBUG
+#ifdef DEBUG_INTENSIVELY
             g_message("duration = %lu",
                       mad_timer_count(header.duration,
                                       MAD_UNITS_MILLISECONDS));
             g_message("size = %d", stream.next_frame - stream.this_frame);
 #endif
+#endif
             mad_timer_add(&info->duration, header.duration);
             data_used += stream.next_frame - stream.this_frame;
             if (info->frames == 1) {
@@ -301,7 +304,6 @@
             if (fast && info->frames >= N_AVERAGE_FRAMES) {
                 float frame_size = ((double) data_used) / N_AVERAGE_FRAMES;
                 info->frames = (info->size - tagsize) / frame_size;
-                //int frame_frac = (info->size - tagsize) % frame_size;
                 info->duration.seconds /= N_AVERAGE_FRAMES;
                 info->duration.fraction /= N_AVERAGE_FRAMES;
                 mad_timer_multiply(&info->duration, info->frames);
@@ -309,7 +311,6 @@
                 g_message("using fast playtime calculation");
                 g_message("data used = %d [tagsize=%d framesize=%f]",
                           data_used, tagsize, frame_size);
-                //g_message ("frame_size = %f [frac=%d]", frame_size, frame_frac);
                 g_message("frames = %d, frequecy = %d, channels = %d",
                           info->frames, info->freq, info->channels);
                 long millis = mad_timer_count(info->duration,
@@ -335,14 +336,15 @@
 #ifdef DEBUG
     g_message("e: scan_file");
 #endif                          /* DEBUG */
-    return (info->frames != 0 || info->remote == TRUE);
+//    return info->frames != 0;
+    return (info->frames != 0 || info->remote == TRUE); // suspicious
 }
 
 gpointer decode_loop(gpointer arg)
 {
     unsigned char buffer[BUFFER_SIZE];
     int len;
-    int seek_skip = 0;
+    gboolean seek_skip = FALSE;
     int remainder = 0;
     gint tlen;
 
@@ -363,12 +365,20 @@
     mad_stream_init(&stream);
     mad_synth_init(&synth);
 
-    if (!mad_plugin->output->
-        open_audio(info->fmt, info->freq, info->channels)) {
+    if(!info->playback){
+        g_print("decode: playback == NULL\n");
+        return NULL;
+    }
+
+    if (!info->playback->output->open_audio(info->fmt, info->freq, info->channels)) {
+        g_mutex_lock(pb_mutex);
+        info->playback->error = TRUE;
+        info->playback->eof = 1;
+        g_mutex_unlock(pb_mutex);        
         audmad_error("failed to open audio output: %s",
-                      mad_plugin->output->description);
+                      info->playback->output->description);
         g_message("failed to open audio output: %s",
-                  mad_plugin->output->description);
+                  info->playback->output->description);
         return NULL;
     }
 
@@ -378,6 +388,7 @@
     info->title =
         xmms_get_titlestring(xmms_get_gentitle_format(), info->tuple);
 
+    
     tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS),
     
     mad_plugin->set_info(info->title,
@@ -386,7 +397,7 @@
 
     /* main loop */
     do {
-        if (info->playback->playing == 0) {
+        if (!info->playback->playing) {
 #ifdef DEBUG
             g_message("decode: stop signaled");
 #endif                          /* DEBUG */
@@ -427,14 +438,19 @@
                     if (--skip == 0)
                         mad_synth_frame(&synth, &frame);
                 }
-                else if (!MAD_RECOVERABLE(stream.error))
+                else if (!MAD_RECOVERABLE(stream.error)) {
+                    g_mutex_lock(pb_mutex);
+                    info->playback->error = TRUE;
+                    info->playback->eof = 1;
+                    g_mutex_unlock(pb_mutex);
                     break;
+                }
             }
             while (skip);
-            seek_skip = 0;
+            seek_skip = FALSE;
         }
 
-        while (!info->playback->playing == 0) {
+        while (info->playback->playing) {
             if (info->seek != -1 && !info->remote) {
 #ifdef DEBUG
                 g_message("seeking: %d", info->seek);
@@ -448,6 +464,9 @@
                 mad_timer_set(&info->pos, info->seek, 0, 0);
                 new_position =
                     ((double) info->seek / (double) seconds) * info->size;
+
+                if(new_position < 0)
+                    new_position = 0;
 #ifdef DEBUG
                 g_message("seeking to: %d bytes", new_position);
 #endif
@@ -456,18 +475,17 @@
                 mad_frame_mute(&frame);
                 mad_synth_mute(&synth);
                 stream.error = MAD_ERROR_BUFLEN;
-                mad_plugin->output->flush(mad_timer_count
-                                         (info->pos,
-                                          MAD_UNITS_MILLISECONDS));
+                info->playback->output->flush(mad_timer_count(info->pos, MAD_UNITS_MILLISECONDS));
                 stream.sync = 0;
                 info->seek = -1;
-                seek_skip = 1;
+                seek_skip = TRUE;
                 break;
             }
 
             if (mad_header_decode(&frame.header, &stream) == -1) {
-                if (!MAD_RECOVERABLE(stream.error))
+                if (!MAD_RECOVERABLE(stream.error)) {
                     break;
+                }
                 if (stream.error == MAD_ERROR_LOSTSYNC) {
                     /* ignore LOSTSYNC due to ID3 tags */
                     int tagsize = id3_tag_query(stream.this_frame,
@@ -500,9 +518,7 @@
 
             if (info->freq != frame.header.samplerate
                 || info->channels !=
-                (guint) MAD_NCHANNELS(&frame.header))
-	    {
-		tlen = mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS);
+                (guint) MAD_NCHANNELS(&frame.header)) {
 #ifdef DEBUG
                 g_message("re-opening audio due to change in audio type");
                 g_message("old: frequency = %d, channels = %d", info->freq,
@@ -511,24 +527,24 @@
                           frame.header.samplerate,
                           (guint) MAD_NCHANNELS(&frame.header));
 #endif                          /* DEBUG */
-
                 info->freq = frame.header.samplerate;
                 info->channels = MAD_NCHANNELS(&frame.header);
-                mad_plugin->output->close_audio();
-                if (!mad_plugin->output->open_audio(info->fmt, info->freq,
+                info->playback->output->close_audio();
+                if (!info->playback->output->open_audio(info->fmt, info->freq,
                                                    info->channels)) {
+                    g_mutex_lock(pb_mutex);
+                    info->playback->error = TRUE;
+                    info->playback->eof = 1;
+                    g_mutex_unlock(pb_mutex);
                     audmad_error("failed to re-open audio output: %s",
-                                  mad_plugin->output->description);
+                                  info->playback->output->description);
                 }
-
-		mad_plugin->set_info(info->title,
-                        tlen != 0 ? tlen : -1,
-                        info->bitrate, info->freq, info->channels);
             }
-            if (info->playback->playing == 0)
+            if (!info->playback->playing)
                 break;
             mad_synth_frame(&synth, &frame);
             mad_stream_sync(&stream);
+
             write_output(info, &synth.pcm, &frame.header);
             mad_timer_add(&info->pos, frame.header.duration);
         }
@@ -540,17 +556,30 @@
     mad_stream_finish(&stream);
     mad_synth_finish(&synth);
 
-    if (!info->playback->playing == 0) {
-        mad_plugin->output->buffer_free();
-        mad_plugin->output->buffer_free();
-        while (mad_plugin->output->buffer_playing()) {
+    if (info->playback->playing) {
+        GTimeVal sleeptime;
+
+        info->playback->output->buffer_free();
+        info->playback->output->buffer_free();
+        while (info->playback->output->buffer_playing()) {
 #ifdef DEBUG
             g_message("f: buffer_playing=%d",
-                      mad_plugin->output->buffer_playing());
+                      info->playback->output->buffer_playing());
 #endif
-            xmms_usleep(10000);
-            if (info->playback->playing == 0)
+            g_get_current_time(&sleeptime);
+            sleeptime.tv_usec += 500000;
+            if(sleeptime.tv_usec >= 1000000) {
+                sleeptime.tv_sec += 1;
+                sleeptime.tv_usec -= 1000000;
+            }
+
+            g_mutex_lock(mad_mutex);
+            g_cond_timed_wait(mad_cond, mad_mutex, &sleeptime);
+            if (!info->playback->playing) {
+                g_mutex_unlock(mad_mutex);
                 break;
+            }
+            g_mutex_unlock(mad_mutex);
         }
     }
 #ifdef DEBUG
@@ -560,8 +589,10 @@
     bmp_title_input_free(info->tuple);
     info->tuple = NULL;
 
-    mad_plugin->output->close_audio();
+    info->playback->output->close_audio();
+    g_mutex_lock(mad_mutex);
     info->playback->playing = 0;
+    g_mutex_unlock(mad_mutex);
     g_thread_exit(0);
     return NULL; /* dummy */
 }
--- a/src/madplug/fileinfo.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/fileinfo.c	Tue Feb 06 12:11:42 2007 -0800
@@ -62,6 +62,8 @@
     if (data == NULL)
         return;
 
+    /* printf ("updating id3: %s: %s\n", frame_name, data); */
+
     /*
      * An empty string removes the frame altogether.
      */
@@ -77,31 +79,37 @@
         id3_tag_attachframe(tag, frame);
     }
 
-    if (frame_name == ID3_FRAME_COMMENT) {
+    // setup ucs4 string
+    if(audmad_config.sjis) {
+        ucs4 = id3_latin1_ucs4duplicate((id3_latin1_t *) data);
+    }
+    else {
+        ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) data);
+    }
+
+    // set encoding
+    field = id3_frame_field(frame, 0);
+    id3_field_settextencoding(field, audmad_config.sjis ? ID3_FIELD_TEXTENCODING_ISO_8859_1 :
+			      ID3_FIELD_TEXTENCODING_UTF_8);
+        
+    // setup genre code
+    if (!strcmp(frame_name, ID3_FRAME_GENRE)) {
+        char *tmp;
+        int index = id3_genre_number(ucs4);
+        g_free(ucs4);
+        tmp = g_strdup_printf("%d", index);
+        ucs4 = id3_latin1_ucs4duplicate((unsigned char *) tmp);
+    }
+
+    // write string
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT)) {
         field = id3_frame_field(frame, 3);
         field->type = ID3_FIELD_TYPE_STRINGFULL;
+        res = id3_field_setfullstring(field, ucs4);
     }
     else {
         field = id3_frame_field(frame, 1);
         field->type = ID3_FIELD_TYPE_STRINGLIST;
-    }
-
-    id3_field_settextencoding(field, ID3_FIELD_TEXTENCODING_UTF_8);
-
-    ucs4 = id3_utf8_ucs4duplicate((const unsigned char *) data);
-
-    if (frame_name == ID3_FRAME_GENRE) {
-        char *tmp;
-        int index = id3_genre_number(ucs4);
-        g_free(ucs4);
-        tmp = g_strdup_printf("%d", index);
-        ucs4 = id3_utf8_ucs4duplicate((unsigned char *) tmp);
-    }
-
-    if (frame_name == ID3_FRAME_COMMENT) {
-        res = id3_field_setfullstring(field, ucs4);
-    }
-    else {
         res = id3_field_setstrings(field, 1, &ucs4);
     }
 
@@ -117,10 +125,10 @@
 
 static void save_cb(GtkWidget * w, gpointer data)
 {
-    gchar *text;
+    gchar *text, *sjis;
     struct id3_file *id3file;
     struct id3_tag *id3tag;
-    char *codeset;
+    char *encoding;
 
     if (info.remote)
         return;
@@ -130,55 +138,78 @@
     if (!id3file) {
         id3tag = id3_tag_new();
         id3_tag_clearframes(id3tag);
+        id3tag->options |= ID3_TAG_OPTION_ID3V1;
         if (!id3file) {
             xmms_show_message("File Info", "Couldn't open file!", "Ok",
                               FALSE, NULL, NULL);
             return;
         }
     }
-
     id3tag = id3_file_tag(id3file);
+    id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);    /* enables id3v1 */
+//    id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, 0);    /* disables id3v1 */
     if (!id3tag) {
         id3tag = id3_tag_new();
     }
 
+    encoding = audmad_config.sjis ? "SJIS" : "UTF-8";
+
     text = gtk_editable_get_chars(GTK_EDITABLE(title_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_TITLE, text);
+    sjis = g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_TITLE, sjis);
     free(text);
+    free(sjis);
 
     text = gtk_editable_get_chars(GTK_EDITABLE(artist_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_ARTIST, text);
+    sjis = g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_ARTIST, sjis);
     free(text);
+    free(sjis);
 
     text = gtk_editable_get_chars(GTK_EDITABLE(album_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_ALBUM, text);
+    sjis =
+        g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_ALBUM, sjis);
     free(text);
+    free(sjis);
 
     text = gtk_editable_get_chars(GTK_EDITABLE(year_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_YEAR, text);
+    sjis =
+        g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_YEAR, sjis);
     free(text);
+    free(sjis);
 
     text = gtk_editable_get_chars(GTK_EDITABLE(comment_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_COMMENT, text);
+    sjis =
+        g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_COMMENT, sjis);
     free(text);
+    free(sjis);
 
     text = gtk_editable_get_chars(GTK_EDITABLE(tracknum_entry), 0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_TRACK, text);
+    sjis =
+        g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_TRACK, sjis);
     free(text);
+    free(sjis);
 
-    text =
-        gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(genre_combo)->entry),
+    text = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(genre_combo)->entry),
                                0, -1);
-    update_id3_frame(id3tag, ID3_FRAME_GENRE, text);
+    sjis = g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+    update_id3_frame(id3tag, ID3_FRAME_GENRE, sjis);
     free(text);
+    free(sjis);
 
     if (id3_file_update(id3file) != 0) {
         xmms_show_message("File Info", "Couldn't write tag!", "Ok", FALSE,
                           NULL, NULL);
     }
     id3_file_close(id3file);
+//    gtk_widget_destroy(window);
 }
 
+#if 0
 static void remove_id3_cb(GtkWidget * w, gpointer data)
 {
     struct id3_file *id3file;
@@ -211,6 +242,277 @@
     gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
     gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
 }
+#endif
+
+static void remove_id3_cb(GtkWidget * w, gpointer data)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+
+    /* read tag from file */
+    id3file = id3_file_open(info.filename, ID3_FILE_MODE_READWRITE);
+    if (!id3file)
+        return;
+
+    id3tag = id3_file_tag(id3file);
+    if(id3tag) {
+        /* since current libid3tag cannot delete tag completely, just add a dummy. */
+        const char *dummy = "";
+        update_id3_frame(id3tag, ID3_FRAME_TITLE, dummy);
+        update_id3_frame(id3tag, ID3_FRAME_ARTIST, dummy);
+        update_id3_frame(id3tag, ID3_FRAME_ALBUM, dummy);
+        update_id3_frame(id3tag, ID3_FRAME_YEAR, dummy);
+        update_id3_frame(id3tag, ID3_FRAME_TRACK, dummy);
+        update_id3_frame(id3tag, ID3_FRAME_GENRE, "Other");
+        update_id3_frame(id3tag, ID3_FRAME_COMMENT, dummy);
+
+        if (id3_file_update(id3file) != 0) {
+            xmms_show_message("File Info", "Couldn't write tag!", "OK", FALSE,
+                              NULL, NULL);
+        }
+    }
+
+    id3_file_close(id3file);
+
+    gtk_entry_set_text(GTK_ENTRY(title_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(artist_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(album_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(comment_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(year_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(tracknum_entry), "");
+    gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "");
+    gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
+    gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
+    
+//    gtk_widget_destroy(window);
+}
+
+#if 0
+void create_window()
+{
+    GtkWidget *vbox, *hbox, *left_vbox, *table;
+    GtkWidget *mpeg_frame, *mpeg_box;
+    GtkWidget *label, *filename_hbox;
+    GtkWidget *bbox, *save, *remove_id3, *cancel;
+
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
+    gtk_signal_connect(GTK_OBJECT(window), "destroy",
+                       GTK_SIGNAL_FUNC(close_window), &window);
+    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
+
+    vbox = gtk_vbox_new(FALSE, 10);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+
+    filename_hbox = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0);
+
+    label = gtk_label_new("Filename:");
+    gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0);
+    filename_entry = gtk_entry_new();
+    gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE);
+    gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE,
+                       0);
+
+    hbox = gtk_hbox_new(FALSE, 10);
+    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+
+    left_vbox = gtk_vbox_new(FALSE, 10);
+    gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0);
+
+    id3_frame = gtk_frame_new("ID3 Tag:");
+    gtk_box_pack_start(GTK_BOX(left_vbox), id3_frame, FALSE, FALSE, 0);
+
+    table = gtk_table_new(5, 5, FALSE);
+    gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+    gtk_container_add(GTK_CONTAINER(id3_frame), table);
+
+    label = gtk_label_new("Title:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    title_entry = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Artist:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    artist_entry = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Album:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    album_entry = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Comment:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    comment_entry = gtk_entry_new();
+    gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Year:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    year_entry = gtk_entry_new();
+    gtk_widget_set_usize(year_entry, 40, -1);
+    gtk_table_attach(GTK_TABLE(table), year_entry, 1, 2, 4, 5,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Track number:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    tracknum_entry = gtk_entry_new();
+    gtk_widget_set_usize(tracknum_entry, 40, -1);
+    gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    label = gtk_label_new("Genre:");
+    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
+    gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL,
+                     GTK_FILL, 5, 5);
+
+    genre_combo = gtk_combo_new();
+    gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry),
+                           FALSE);
+    if (!genre_list) {
+        int i = 0;
+        const id3_ucs4_t *ucs4 = id3_genre_index(i);
+        while (ucs4) {
+            genre_list =
+                g_list_append(genre_list, id3_ucs4_latin1duplicate(ucs4));
+            i++;
+            ucs4 = id3_genre_index(i);
+        }
+    }
+    gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list);
+
+    gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5);
+
+    bbox = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+    gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+    gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0);
+
+    save = gtk_button_new_with_label("Save");
+    gtk_signal_connect(GTK_OBJECT(save), "clicked",
+                       GTK_SIGNAL_FUNC(save_cb), NULL);
+    GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0);
+    gtk_widget_grab_default(save);
+
+    remove_id3 = gtk_button_new_with_label("Remove ID3");
+    gtk_signal_connect(GTK_OBJECT(remove_id3), "clicked",
+                       GTK_SIGNAL_FUNC(remove_id3_cb), NULL);
+    GTK_WIDGET_SET_FLAGS(remove_id3, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), remove_id3, TRUE, TRUE, 0);
+
+    cancel = gtk_button_new_with_label("Cancel");
+    gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
+                              GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                              GTK_OBJECT(window));
+    GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+    gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+    mpeg_frame = gtk_frame_new("MPEG Info:");
+    gtk_box_pack_start(GTK_BOX(hbox), mpeg_frame, FALSE, FALSE, 0);
+
+    mpeg_box = gtk_vbox_new(FALSE, 5);
+    gtk_container_add(GTK_CONTAINER(mpeg_frame), mpeg_box);
+    gtk_container_set_border_width(GTK_CONTAINER(mpeg_box), 10);
+    gtk_box_set_spacing(GTK_BOX(mpeg_box), 0);
+
+    mpeg_level = gtk_label_new("");
+    gtk_widget_set_usize(mpeg_level, 120, -2);
+    gtk_misc_set_alignment(GTK_MISC(mpeg_level), 0, 0);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_level, FALSE, FALSE, 0);
+
+    mpeg_bitrate = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_bitrate), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_bitrate), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_bitrate, FALSE, FALSE, 0);
+
+    mpeg_samplerate = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_samplerate), 0, 0);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_samplerate, FALSE, FALSE,
+                       0);
+
+    mpeg_flags = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_flags), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_flags), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_flags, FALSE, FALSE, 0);
+
+    mpeg_frames = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_frames), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_frames), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_frames, FALSE, FALSE, 0);
+
+    mpeg_duration = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_duration), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_duration), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_duration, FALSE, FALSE, 0);
+
+    mpeg_replaygain = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_replaygain), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_replaygain), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_replaygain, FALSE, FALSE,
+                       0);
+    mpeg_replaygain2 = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_replaygain2), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_replaygain2), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_replaygain2, FALSE, FALSE,
+                       0);
+    mpeg_replaygain3 = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_replaygain3), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_replaygain3), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_replaygain3, FALSE, FALSE,
+                       0);
+    mpeg_replaygain4 = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_replaygain4), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_replaygain4), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_replaygain4, FALSE, FALSE,
+                       0);
+    mp3gain1 = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mp3gain1), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mp3gain1), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mp3gain1, FALSE, FALSE, 0);
+    mp3gain2 = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mp3gain2), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mp3gain2), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mp3gain2, FALSE, FALSE, 0);
+
+    mpeg_fileinfo = gtk_label_new("");
+    gtk_misc_set_alignment(GTK_MISC(mpeg_fileinfo), 0, 0);
+    gtk_label_set_justify(GTK_LABEL(mpeg_fileinfo), GTK_JUSTIFY_LEFT);
+    gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_fileinfo, FALSE, FALSE, 0);
+
+    gtk_widget_show_all(window);
+}
+#endif
 
 static void
 change_buttons(GtkWidget * object)
@@ -500,7 +802,7 @@
 #ifndef NOGUI
     gchar *title;
     gchar message[128];
-    static char const *const layer_str[3] = { "MPEG-1 Layer I", "MPEG-1 Layer II", "MPEG-1 Layer III" };
+    static char const *const layer_str[3] = { "I", "II", "III" };
     static char const *const mode_str[4] = {
         ("single channel"), ("dual channel"), "joint stereo", "stereo"
     };
@@ -509,13 +811,20 @@
 #ifdef DEBUG
     g_message("f: audmad_get_file_info: %s\n", filename);
 #endif
+    input_init(&info, filename);
+
+    if (!strncasecmp("http://", filename, strlen("http://")) ||
+	!strncasecmp("https://", filename, strlen("https://"))) {
+        info.remote = TRUE;
+	return; //tentative
+    }
+
     utf_filename = str_to_utf8(filename);
     create_window();
 
-    input_init(&info, filename);
-    input_get_info(&info, FALSE);
+    input_get_info(&info, info.remote ? TRUE : audmad_config.fast_play_time_calc);
 
-    title = g_strdup_printf("%s - Audacious", g_basename(filename));
+    title = g_strdup_printf("File Info - %s", g_basename(filename));
     gtk_window_set_title(GTK_WINDOW(window), title);
     g_free(title);
 
@@ -545,13 +854,13 @@
 
     id3_frame_to_entry(ID3_FRAME_TRACK, GTK_ENTRY(tracknum_entry));
     id3_frame_to_entry(ID3_FRAME_COMMENT, GTK_ENTRY(comment_entry));
-    snprintf(message, 127, "%s", layer_str[info.mpeg_layer - 1]);
+    snprintf(message, 127, "Layer %s", layer_str[info.mpeg_layer - 1]);
     gtk_label_set_text(GTK_LABEL(mpeg_level), message);
     if (info.vbr) {
         snprintf(message, 127, "VBR (avg. %d kbps)", info.bitrate / 1000);
     }
     else {
-        snprintf(message, 127, "%d KBit/s", info.bitrate / 1000);
+        snprintf(message, 127, "%d kbps", info.bitrate / 1000);
     }
     gtk_label_set_text(GTK_LABEL(mpeg_bitrate), message);
     snprintf(message, 127, "%d Hz", info.freq);
--- a/src/madplug/input.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/input.c	Tue Feb 06 12:11:42 2007 -0800
@@ -66,6 +66,14 @@
 
 extern gboolean scan_file(struct mad_info_t *info, gboolean fast);
 
+// new VFS handles url.
+static void input_parse_url(struct mad_info_t *info)
+{
+    info->filename = g_strdup(info->url);
+    return;
+}
+
+
 /**
  * init the mad_info_t struct.
  */
@@ -101,12 +109,13 @@
     info->mp3gain_minmax_str = 0;
 
     info->tuple = NULL;
-    info->filename = g_strdup(url);
+
+    input_parse_url(info);
 
     info->infile = vfs_fopen(info->filename, "rb");
-    if (info->infile == NULL)
+    if (info->infile == NULL) {
         return FALSE;
-
+    }
     // obtain file size
     vfs_fseek(info->infile, 0, SEEK_END);
     info->size = vfs_ftell(info->infile);
@@ -114,7 +123,6 @@
     info->remote = info->size == 0 ? TRUE : FALSE;
 
 #ifdef DEBUG
-    g_message("i: info->size == %lu", info->size);
     g_message("e: input_init");
 #endif
     return TRUE;
@@ -159,7 +167,7 @@
 
     tail = (id3_ucs4_t *)string + mad_ucs4len((id3_ucs4_t *)string);
 
-    ret = g_malloc0(1024); // realloc() is too picky
+    ret = g_malloc0(1024);
 
     for(ptr = (id3_ucs4_t *)string; *ptr != 0 && ptr <= tail; ptr++) {
         if(*ptr == '(') {
@@ -168,7 +176,6 @@
                     end++;
                 }
                 end++; //include trailing ')'
-//                ret = g_realloc(ret, BYTES(end - ptr + 1));
                 memcpy(ret, ptr, BYTES(end - ptr));
                 ret_len += (end - ptr);
                 *(ret + ret_len) = 0; //terminate
@@ -192,7 +199,6 @@
 
                 tmp_len = mad_ucs4len(genre);
 
-//                ret = g_realloc(ret, BYTES(ret_len + tmp_len + 1));
                 memcpy(ret + BYTES(ret_len), genre, BYTES(tmp_len));
 
                 ret_len += tmp_len;
@@ -231,14 +237,12 @@
 
                 tmp_len = mad_ucs4len(genre);
 
-//                ret = g_realloc(ret, BYTES(ret_len + tmp_len + 1));
                 memcpy(ret + BYTES(ret_len), genre, BYTES(tmp_len));
 
                 ret_len += tmp_len;
                 *(ret + ret_len) = 0; //terminate
             }
             else { // plain text
-//                ret = g_realloc(ret, BYTES(end - ptr + 1));
 #ifdef DEBUG
                 printf("plain!\n");
                 printf("ret_len = %d\n", ret_len);
@@ -257,16 +261,19 @@
 gchar *input_id3_get_string(struct id3_tag * tag, char *frame_name)
 {
     gchar *rtn;
+    gchar *rtn2;
     const id3_ucs4_t *string_const;
     id3_ucs4_t *string;
+    id3_ucs4_t *ucsptr;
     struct id3_frame *frame;
     union id3_field *field;
+    gboolean flagutf = FALSE;
 
     frame = id3_tag_findframe(tag, frame_name, 0);
     if (!frame)
         return NULL;
 
-    if (frame_name == ID3_FRAME_COMMENT)
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT))
         field = id3_frame_field(frame, 3);
     else
         field = id3_frame_field(frame, 1);
@@ -274,7 +281,7 @@
     if (!field)
         return NULL;
 
-    if (frame_name == ID3_FRAME_COMMENT)
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT))
         string_const = id3_field_getfullstring(field);
     else
         string_const = id3_field_getstrings(field, 0);
@@ -284,21 +291,38 @@
 
     string = mad_ucs4dup((id3_ucs4_t *)string_const);
 
-    if (frame_name == ID3_FRAME_GENRE) {
+    if (!strcmp(frame_name, ID3_FRAME_GENRE)) {
         id3_ucs4_t *string2 = NULL;
         string2 = mad_parse_genre(string);
         g_free((void *)string);
         string = string2;
     }
 
-    {
-        id3_utf8_t *string2 = id3_ucs4_utf8duplicate(string);
-        rtn = str_to_utf8(string2);
-        g_free(string2);
+    ucsptr = (id3_ucs4_t *)string;
+    while (*ucsptr) {
+        if (*ucsptr > 0x000000ffL) {
+            flagutf = TRUE;
+            break;
+        }
+        ucsptr++;
     }
 
+    if (flagutf) {
 #ifdef DEBUG
-    g_print("i: string = %s\n", rtn);
+        g_print("aud-mad: flagutf!\n");
+#endif
+        rtn = (gchar *)id3_ucs4_utf8duplicate(string);
+    }
+    else {
+        rtn = (gchar *)id3_ucs4_latin1duplicate(string);
+        rtn2 = str_to_utf8(rtn);
+        free(rtn);
+        rtn = rtn2;
+    }
+    g_free(string);
+    string = NULL;
+#ifdef DEBUG
+    g_print("string = %s\n", rtn);
 #endif
     return rtn;
 }
@@ -379,15 +403,14 @@
     input_read_replaygain(info);
 
     /* scan mp3 file, decoding headers unless fast_scan is set */
-    if (scan_file(info, fast_scan) == FALSE)
+    if (scan_file(info, fast_scan) == FALSE) {
         return FALSE;
-
+    }
     /* reset the input file to the start */
-    vfs_rewind(info->infile);
+    vfs_fseek(info->infile, 0, SEEK_SET);
     info->offset = 0;
 
-    if (info->remote)
-    {
+    if(info->remote){
         gchar *stream_name = vfs_get_metadata(info->infile, "stream-name");
         gchar *track_name = vfs_get_metadata(info->infile, "track-name");
         gchar *tmp = NULL;
@@ -407,8 +430,7 @@
     }
 
     /* use the filename for the title as a last resort */
-    if (!info->title)
-    {
+    if (!info->title) {
         char *pos = strrchr(info->filename, DIR_SEPARATOR);
         if (pos)
             info->title = g_strdup(pos + 1);
@@ -423,29 +445,33 @@
 }
 
 
+
 /**
  * Read data from the source given my madinfo into the buffer
  * provided.  Return the number of bytes read.
  * @return 0 on EOF
  * @return -1 on error
  */
+// this function may be called before info->playback initialized.
 int
 input_get_data(struct mad_info_t *madinfo, guchar * buffer,
                int buffer_size)
 {
     int len = 0;
 #ifdef DEBUG
-//  g_message ("f: input_get_data: %d", buffer_size);
+#ifdef DEBUG_INTENSIVELY
+  g_message ("f: input_get_data: %d", buffer_size);
 #endif
-
+#endif
     /* simply read to data from the file */
-    len = vfs_fread(buffer, 1, buffer_size, madinfo->infile);
+    len = vfs_fread(buffer, 1, buffer_size, madinfo->infile); //vfs_fread returns num of element.
 
-    if (len == 0 && madinfo->playback)
-        madinfo->playback->eof = TRUE;
-
-    if (madinfo->remote)
-    {
+    if(len == 0){
+	    if(madinfo->playback)
+		    madinfo->playback->eof = TRUE;
+    }
+    
+    if(madinfo->remote) {
         gchar *stream_name = vfs_get_metadata(madinfo->infile, "stream-name");
         gchar *track_name = vfs_get_metadata(madinfo->infile, "track-name");
         gchar *tmp = NULL;
@@ -459,13 +485,15 @@
         madinfo->tuple->album_name = g_strdup(stream_name);
         tmp = g_strdup_printf("%s (%s)", track_name, stream_name);
         mad_plugin->set_info(tmp,
-                             -1, // indicates the stream is unseekable
-                             madinfo->bitrate, madinfo->freq, madinfo->channels);
+                             -1, // indicate the stream is unseekable
+			     madinfo->bitrate, madinfo->freq, madinfo->channels);
         g_free(tmp); g_free(stream_name); g_free(track_name);
     }
-
+    
 #ifdef DEBUG
-//  g_message ("e: input_get_data: size=%d offset=%d", len, madinfo->offset);
+#ifdef DEBUG_INTENSIVELY
+    g_message ("e: input_get_data: size=%d offset=%d", len, madinfo->offset);
+#endif
 #endif
     madinfo->offset += len;
     return len;
--- a/src/madplug/input.h	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/input.h	Tue Feb 06 12:11:42 2007 -0800
@@ -23,13 +23,11 @@
 #define INPUT_H
 
 #include "plugin.h"
-
 gboolean input_init(struct mad_info_t *songinfo, const gchar * url);
 gboolean input_term(struct mad_info_t *songinfo);
 gboolean input_get_info(struct mad_info_t *songinfo, gboolean fast_scan);
 gint input_get_data(struct mad_info_t *songinfo, guchar * buffer,
                     gint buffer_size);
-gint input_udp_read();
 gchar *input_id3_get_string(struct id3_tag *tag, char *frame_name);
 
 #endif                          /* ! INPUT_H */
--- a/src/madplug/plugin.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/plugin.c	Tue Feb 06 12:11:42 2007 -0800
@@ -37,8 +37,10 @@
  * Global variables
  */
 struct audmad_config_t audmad_config;   /**< global configuration */
-static GStaticMutex mutex;
 InputPlugin *mad_plugin = NULL;
+GMutex *mad_mutex;
+GMutex *pb_mutex;
+GCond *mad_cond;
 
 /*
  * static variables
@@ -69,6 +71,7 @@
     return ext;
 }
 
+
 void audmad_config_compute(struct audmad_config_t *config)
 {
     /* set some config parameters by parsing text fields 
@@ -99,6 +102,7 @@
     audmad_config.fast_play_time_calc = TRUE;
     audmad_config.use_xing = TRUE;
     audmad_config.dither = TRUE;
+    audmad_config.sjis = FALSE;
     audmad_config.pregain_db = "+0.00";
     audmad_config.replaygain.enable = TRUE;
     audmad_config.replaygain.track_mode = FALSE;
@@ -112,6 +116,7 @@
         bmp_cfg_db_get_bool(db, "MAD", "use_xing",
                             &audmad_config.use_xing);
         bmp_cfg_db_get_bool(db, "MAD", "dither", &audmad_config.dither);
+        bmp_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config.sjis);
         bmp_cfg_db_get_bool(db, "MAD", "hard_limit",
                             &audmad_config.hard_limit);
         bmp_cfg_db_get_string(db, "MAD", "pregain_db",
@@ -122,15 +127,13 @@
                             &audmad_config.replaygain.track_mode);
         bmp_cfg_db_get_string(db, "MAD", "RG.default_db",
                               &audmad_config.replaygain.default_db);
-        bmp_cfg_db_get_bool(db, "MAD", "title_override",
-                            &audmad_config.title_override);
-        bmp_cfg_db_get_string(db, "MAD", "id3_format",
-                              &audmad_config.id3_format);
 
         bmp_cfg_db_close(db);
     }
 
-    g_static_mutex_init(&mutex);
+    mad_mutex = g_mutex_new();
+    pb_mutex = g_mutex_new();
+    mad_cond = g_cond_new();
     audmad_config_compute(&audmad_config);
 
 }
@@ -183,6 +186,8 @@
         ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3];
 }
 
+#if 0
+// XXX: can't add remote stream from add URL dialog. temporally disabled.
 // audacious vfs fast version
 static int audmad_is_our_fd(char *filename, VFSFile *fin)
 {
@@ -238,6 +243,64 @@
 
     return 1;
 }
+#endif
+
+// this function will be replaced soon.
+static int audmad_is_our_fd(char *filename, VFSFile *fin)
+{
+    int rtn = 0;
+    guchar check[4];
+
+    info.remote = FALSE; //awkward...
+
+#ifdef DEBUG
+    g_message("audmad: filename = %s\n", filename);
+#endif
+
+    // 0. if url is beginning with http://, take it blindly.
+    if (!strncasecmp("http://", filename, strlen("http://")) ||
+	!strncasecmp("https://", filename, strlen("https://"))) {
+        g_message("audmad: remote\n");
+        info.remote = TRUE;
+        return 1; //ours
+    }
+
+    // 1. check embeded signature 
+    if (fin && vfs_fread(check, 1, 4, fin) == 4) {
+        /*
+         * or three bytes are "ID3"
+         */
+        if (mp3_head_check(check)) {
+            rtn = 1;
+        }
+        else if (memcmp(check, "ID3", 3) == 0) {
+            rtn = 1;
+        }
+        else if (memcmp(check, "RIFF", 4) == 0) {
+            vfs_fseek(fin, 4, SEEK_CUR);
+            vfs_fread(check, 1, 4, fin);
+
+            if (memcmp(check, "RMP3", 4) == 0) {
+                rtn = 1;
+            }
+        }
+    }
+    // 2. exclude files with folloing extensions
+    if (strcasecmp("flac", filename + strlen(filename) - 4) == 0 ||
+        strcasecmp("mpc", filename + strlen(filename) - 3) == 0 ||
+        strcasecmp("tta", filename + strlen(filename) - 3) == 0) {
+        rtn = 0;
+        goto tail;
+    }
+
+    // 3. if we haven't found any signature, take the files with .mp3 extension.
+    if (rtn == 0 && strcasecmp("mp3", filename + strlen(filename) - 3) == 0) {
+        rtn = 1;
+    }
+
+  tail:
+    return rtn;
+}
 
 // audacious vfs version
 static int audmad_is_our_file(char *filename)
@@ -261,9 +324,17 @@
 #ifdef DEBUG
     g_message("f: audmad_stop");
 #endif                          /* DEBUG */
-    g_static_mutex_lock(&mutex);
+    g_mutex_lock(mad_mutex);
+    info.playback = playback;
+    g_mutex_unlock(mad_mutex);
+
     if (decode_thread) {
+
+        g_mutex_lock(mad_mutex);
         info.playback->playing = 0;
+        g_mutex_unlock(mad_mutex);
+        g_cond_signal(mad_cond);
+
 #ifdef DEBUG
         g_message("waiting for thread");
 #endif                          /* DEBUG */
@@ -273,11 +344,13 @@
 #endif                          /* DEBUG */
         input_term(&info);
         decode_thread = NULL;
+
     }
-    g_static_mutex_unlock(&mutex);
+#ifdef DEBUG
+    g_message("e: audmad_stop");
+#endif                          /* DEBUG */
 }
 
-
 static void audmad_play_file(InputPlayback *playback)
 {
     gboolean rtn;
@@ -307,20 +380,28 @@
 
 static void audmad_pause(InputPlayback *playback, short paused)
 {
-    mad_plugin->output->pause(paused);
+    g_mutex_lock(pb_mutex);
+    info.playback = playback;
+    g_mutex_unlock(pb_mutex);
+    playback->output->pause(paused);
 }
 
 static void audmad_seek(InputPlayback *playback, int time)
 {
+    g_mutex_lock(pb_mutex);
+    info.playback = playback;
     /* xmms gives us the desired seek time in seconds */
     info.seek = time;
+    g_mutex_unlock(pb_mutex);
+
 }
 
 /**
  * Scan the given file or URL.
  * Fills in the title string and the track length in milliseconds.
  */
-void audmad_get_song_info(char *url, char **title, int *length)
+static void
+audmad_get_song_info(char *url, char **title, int *length)
 {
     struct mad_info_t myinfo;
 #ifdef DEBUG
@@ -329,19 +410,18 @@
 
     input_init(&myinfo, url);
 
-    if (input_get_info(&myinfo, audmad_config.fast_play_time_calc) == TRUE)
-    {
-        *title = strdup(myinfo.title);
+    if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config.fast_play_time_calc) == TRUE) {
+        if(myinfo.tuple->track_name)
+            *title = strdup(myinfo.tuple->track_name);
+        else
+            *title = strdup(url);
         *length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
     }
-    else
-    {
+    else {
         *title = strdup(url);
         *length = -1;
     }
-
     input_term(&myinfo);
-
 #ifdef DEBUG
     g_message("e: audmad_get_song_info");
 #endif                          /* DEBUG */
@@ -409,6 +489,7 @@
 extern void audmad_get_file_info(char *filename);
 extern void audmad_configure();
 
+
 // tuple stuff
 static TitleInput *audmad_get_song_tuple(char *filename)
 {
@@ -428,9 +509,28 @@
     }
 #endif
 
-    if ((file = vfs_fopen(filename, "rb")) != NULL) {
+    // can't re-open remote stream
+    if(info.remote){
         tuple = bmp_title_input_new();
 
+        tuple->track_name = vfs_get_metadata(info.infile, "track-name");
+        tuple->album_name = vfs_get_metadata(info.infile, "stream-name");
+#ifdef DEBUG
+        printf("audmad_get_song_tuple: track_name = %s\n", tuple->track_name);
+        printf("audmad_get_song_tuple: stream_name = %s\n", tuple->album_name);
+#endif
+        tuple->file_name = g_path_get_basename(filename);
+        tuple->file_path = g_path_get_dirname(filename);
+        tuple->file_ext = extname(filename);
+        tuple->length = -1;
+	tuple->mtime = 0; // this indicates streaming
+
+        return tuple;
+    }
+
+    if ((file = vfs_fopen(filename, "rb")) != NULL) {
+
+        tuple = bmp_title_input_new();
         id3file = id3_file_open(filename, ID3_FILE_MODE_READONLY);
 
         if (id3file) {
@@ -466,7 +566,7 @@
                     int length = 0;
                     audmad_get_song_info(filename, &dummy, &length);
                     tuple->length = length;
-		    g_free(dummy);
+                    g_free(dummy);
                 }
 
                 // track number
@@ -485,22 +585,32 @@
                 tuple->comment =
                     input_id3_get_string(tag, ID3_FRAME_COMMENT);
 
-                // mtime
-//                        tuple->mtime = audmad_get_mtime(filename);
-
             }
             id3_file_close(id3file);
         }
+        else {
+            tuple->file_name = g_path_get_basename(filename);
+            tuple->file_path = g_path_get_dirname(filename);
+            tuple->file_ext = extname(filename);
+            // length
+            {
+                char *dummy = NULL;
+                int length = 0;
+                audmad_get_song_info(filename, &dummy, &length);
+                tuple->length = length;
+                g_free(dummy);
+            }
+        }
         vfs_fclose(file);
     }
 #ifdef DEBUG
     g_message("e: mad: audmad_get_song_tuple");
 #endif
-    tuple->formatter = NULL;    //ensure
     return tuple;
 
 }
 
+
 /**
  * Retrieve meta-information about URL.
  * For local files this means ID3 tag etc.
@@ -509,10 +619,12 @@
 {
     TitleInput *tuple = NULL;
 
+#ifdef DEBUG
     g_message("f: mad_get_info: %s", info->filename);
-
-    if (info->remote)
+#endif
+    if (info->remote) {
         return TRUE;
+    }
 
     tuple = audmad_get_song_tuple(info->filename);
     info->title = xmms_get_titlestring(audmad_config.title_override == TRUE ?
@@ -534,9 +646,11 @@
             info->title = g_strdup(pos + 1);
         else
             info->title = g_strdup(info->filename);
-    }
+     }
 
+#ifdef DEBUG
     g_message("e: mad_get_info");
+#endif
     return TRUE;
 }
 
--- a/src/madplug/plugin.h	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/plugin.h	Tue Feb 06 12:11:42 2007 -0800
@@ -22,13 +22,14 @@
 #ifndef AUD_MAD_H
 #define AUD_MAD_H
 
-//#define DEBUG 1
-#undef DEBUG
+#define DEBUG 1
+/* #define DEBUG_INTENSIVELY 1 */
+/* #define DEBUG_DITHER 1 */
 
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "MADPlug"
 
-#include "config.h"
+//#include "config.h" // is it needed when in src tree?
 
 #undef PACKAGE
 #define PACKAGE "audacious-plugins"
@@ -39,7 +40,9 @@
 #include <unistd.h>
 #include <audacious/plugin.h>
 #include <audacious/titlestring.h>
+#include <audacious/util.h>
 #include <audacious/strings.h>
+#include <audacious/vfs.h>
 #include <audacious/i18n.h>
 #include <id3tag.h>
 #include <mad.h>
@@ -48,8 +51,11 @@
 
 struct mad_info_t
 {
+    /* InputPlayback */
     InputPlayback *playback;
-    int seek;
+
+    /* flags */
+    gint seek;      /**< seek time in seconds */
 
     /* state */
     guint current_frame;/**< current mp3 frame */
@@ -94,9 +100,8 @@
     VFSFile *infile;
     gint offset;
 
-    gint remote;
-    struct streamdata_t *sdata;
-                  /**< stream data for remote connections */
+    gboolean remote;
+
 };
 
 struct audmad_config_t
@@ -105,6 +110,7 @@
     gboolean fast_play_time_calc;
     gboolean use_xing;
     gboolean dither;
+    gboolean sjis;
     gboolean hard_limit;
     gchar *pregain_db;          // gain applied to samples at decoding stage.
     gdouble pregain_scale;      // pow(10, pregain/20)
@@ -119,6 +125,11 @@
     gchar *id3_format;
 };
 
+// gcond
+extern GMutex *mad_mutex;
+extern GMutex *pb_mutex;
+extern GCond *mad_cond;
+
 void audmad_config_compute(struct audmad_config_t *config);
 // compute scale values from "_db" strings
 
--- a/src/madplug/replaygain.c	Mon Feb 05 12:28:01 2007 -0800
+++ b/src/madplug/replaygain.c	Tue Feb 06 12:11:42 2007 -0800
@@ -58,7 +58,7 @@
 
 // Reads APE v2.0 tag ending at current pos in fp
 
-static int ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file)
+static int ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file_info)
 {
     unsigned long vsize;
     unsigned long isize;
@@ -110,12 +110,12 @@
             gdouble *scale = NULL;
             gchar **str = NULL;
             if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_GAIN") == 0) {
-                scale = &file->replaygain_album_scale;
-                str = &file->replaygain_album_str;
+                scale = &file_info->replaygain_album_scale;
+                str = &file_info->replaygain_album_str;
             }
             if (uncase_strcmp(p, "REPLAYGAIN_TRACK_GAIN") == 0) {
-                scale = &file->replaygain_track_scale;
-                str = &file->replaygain_track_str;
+                scale = &file_info->replaygain_track_scale;
+                str = &file_info->replaygain_track_str;
             }
             if (str != NULL) {
                 assert(scale != NULL);
@@ -125,12 +125,12 @@
             //* case of peak info tags : */
             str = NULL;
             if (uncase_strcmp(p, "REPLAYGAIN_TRACK_PEAK") == 0) {
-                scale = &file->replaygain_track_peak;
-                str = &file->replaygain_track_peak_str;
+                scale = &file_info->replaygain_track_peak;
+                str = &file_info->replaygain_track_peak_str;
             }
             if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_PEAK") == 0) {
-                scale = &file->replaygain_album_peak;
-                str = &file->replaygain_album_peak_str;
+                scale = &file_info->replaygain_album_peak;
+                str = &file_info->replaygain_album_peak_str;
             }
             if (str != NULL) {
                 *scale = g_strtod(p + isize + 1, NULL);
@@ -143,15 +143,15 @@
                -> 1.501*gain dB
              */
             if (uncase_strcmp(p, "MP3GAIN_UNDO") == 0) {
-                str = &file->mp3gain_undo_str;
-                scale = &file->mp3gain_undo;
+                str = &file_info->mp3gain_undo_str;
+                scale = &file_info->mp3gain_undo;
                 assert(4 < vsize);  /* this tag is +left,+right */
                 *str = g_strndup(p + isize + 1, vsize);
                 *scale = 1.50515 * atoi(*str);
             }
             if (uncase_strcmp(p, "MP3GAIN_MINMAX") == 0) {
-                str = &file->mp3gain_minmax_str;
-                scale = &file->mp3gain_minmax;
+                str = &file_info->mp3gain_minmax_str;
+                scale = &file_info->mp3gain_minmax;
                 *str = g_strndup(p + isize + 1, vsize);
                 assert(4 < vsize);  /* this tag is min,max */
                 *scale = 1.50515 * (atoi((*str) + 4) - atoi(*str));
@@ -194,18 +194,18 @@
     return last_match + 1 - 8 + sizeof(struct APETagFooterStruct) - N;
 }
 
-void input_read_replaygain(struct mad_info_t *file)
+void input_read_replaygain(struct mad_info_t *file_info)
 {
-    file->has_replaygain = FALSE;
-    file->replaygain_album_scale = -1;
-    file->replaygain_track_scale = -1;
-    file->mp3gain_undo = -77;
-    file->mp3gain_minmax = -77;
+    file_info->has_replaygain = FALSE;
+    file_info->replaygain_album_scale = -1;
+    file_info->replaygain_track_scale = -1;
+    file_info->mp3gain_undo = -77;
+    file_info->mp3gain_minmax = -77;
 
 
     VFSFile *fp;
 
-    if ((fp = vfs_fopen(file->filename, "rb")) == NULL)
+    if ((fp = vfs_fopen(file_info->filename, "rb")) == NULL)
         return;
 
     if (vfs_fseek(fp, 0L, SEEK_END) != 0) {
@@ -219,7 +219,7 @@
         // try skipping an id3 tag
         vfs_fseek(fp, pos, SEEK_SET);
         vfs_fseek(fp, try * -128, SEEK_CUR);
-        res = ReadAPE2Tag(fp, file);
+        res = ReadAPE2Tag(fp, file_info);
         ++try;
     }
     if (res != 0) {
@@ -229,7 +229,7 @@
         if (offs <= 0) {        // found !
             vfs_fseek(fp, pos, SEEK_SET);
             vfs_fseek(fp, offs, SEEK_CUR);
-            res = ReadAPE2Tag(fp, file);
+            res = ReadAPE2Tag(fp, file_info);
             if (res != 0) {
                 g_message
                     ("hmpf, was supposed to find a tag.. offs=%d, res=%d",
@@ -238,17 +238,16 @@
         }
     }
 #ifdef DEBUG
-//#if 1
     if (res == 0) {             // got APE tags, show the result
         printf("RG album scale= %g, RG track scale = %g, in %s \n",
-               file->replaygain_album_scale,
-               file->replaygain_track_scale, file->filename);
+               file_info->replaygain_album_scale,
+               file_info->replaygain_track_scale, file_info->filename);
     }
 #endif
 
-    if (file->replaygain_album_scale != -1
-        || file->replaygain_track_scale != -1)
-        file->has_replaygain = TRUE;
+    if (file_info->replaygain_album_scale != -1
+        || file_info->replaygain_track_scale != -1)
+        file_info->has_replaygain = TRUE;
 
     vfs_fclose(fp);
 }