changeset 2341:59addab003d7

- reworked replaygain to use individual pre-gain for the files with RG info and the rest. - default pre-gain have been changed to +6dB for with RG, +0dB for the rest. - new clipping prevention feature using track peak information has been implemented. - reworked preferences dialog. widgets have been categorized by function and all changes will take effect immediately. and also, cancel button can reverts all changes have been done in the current session. - some keys in preferences have been changed.
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Thu, 31 Jan 2008 15:22:15 +0900
parents 47d7a45b26a0
children f40f4ae3d5eb
files src/madplug/configure.c src/madplug/decoder.c src/madplug/dither.c src/madplug/input.c src/madplug/plugin.c src/madplug/plugin.h src/madplug/replaygain.c src/madplug/tuple.c src/madplug/xing.c
diffstat 9 files changed, 742 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- a/src/madplug/configure.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/configure.c	Thu Jan 31 15:22:15 2008 +0900
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define AUD_DEBUG 1 */
+
 #include "plugin.h"
 
 #include <gtk/gtk.h>
@@ -26,110 +28,294 @@
 #include <audacious/configdb.h>
 
 static GtkWidget *configure_win = NULL;
-static GtkWidget *vbox;
-static GtkWidget *fast_playback, *use_xing, *dither, *sjis, *show_avg, *reopen;
-static GtkWidget *RG_enable, *RG_track_mode, *RG_default, *pregain,
-    *hard_limit;
-static GtkWidget *title_id3_box, *title_tag_desc;
-static GtkWidget *title_override, *title_id3_entry;
+static audmad_config_t *oldconfig = NULL; // undo storage
+
+static audmad_config_t *
+duplicate_config(audmad_config_t *orig)
+{
+    audmad_config_t *copy = g_memdup(orig, sizeof(audmad_config_t));
+
+    copy->replaygain.preamp0_db = g_strdup(orig->replaygain.preamp0_db);
+    copy->replaygain.preamp1_db = g_strdup(orig->replaygain.preamp1_db);
+    copy->replaygain.preamp2_db = g_strdup(orig->replaygain.preamp2_db);
+    copy->id3_format = g_strdup(orig->id3_format);
 
-static void configure_win_ok(GtkWidget * widget, gpointer data)
+    return copy;
+}
+
+static void
+dispose_config(audmad_config_t *config)
 {
-    ConfigDb *db;
+    g_free(config->replaygain.preamp0_db);
+    g_free(config->replaygain.preamp1_db);
+    g_free(config->replaygain.preamp2_db);
+    g_free(config->id3_format);
+    g_free(config);
+}
+
+static void
+update_config(gpointer widgets)
+{
     const gchar *text = NULL;
 
-    AUDDBG("saving");
+    AUDDBG("updating\n");
 
-    audmad_config.fast_play_time_calc =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fast_playback));
-    audmad_config.use_xing =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_xing));
-    audmad_config.dither =
+    GtkWidget *dither = g_object_get_data(widgets, "dither");
+    GtkWidget *reopen = g_object_get_data(widgets, "reopen");
+    GtkWidget *fast_playback = g_object_get_data(widgets, "fast_playback");
+    GtkWidget *use_xing = g_object_get_data(widgets, "use_xing");
+    GtkWidget *sjis = g_object_get_data(widgets, "sjis");
+    GtkWidget *show_avg = g_object_get_data(widgets, "show_avg");
+    GtkWidget *RG_enable = g_object_get_data(widgets, "RG_enable");
+    GtkWidget *preamp0 = g_object_get_data(widgets, "preamp0");
+    GtkWidget *preamp1 = g_object_get_data(widgets, "preamp1");
+    GtkWidget *preamp2 = g_object_get_data(widgets, "preamp2");
+    GtkWidget *trackMode = g_object_get_data(widgets, "trackMode");
+    GtkWidget *hard_limit = g_object_get_data(widgets, "hard_limit");
+    GtkWidget *anti_clip = g_object_get_data(widgets, "anti_clip");
+    GtkWidget *title_override = g_object_get_data(widgets, "title_override");
+    GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry");
+
+    //audio
+    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.show_avg_vbr_bitrate =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_avg));
-    audmad_config.force_reopen_audio =
+    audmad_config->force_reopen_audio =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(reopen));
 
-    audmad_config.replaygain.enable =
+    //metadata
+    audmad_config->fast_play_time_calc =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fast_playback));
+    audmad_config->use_xing =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_xing));
+    audmad_config->sjis =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sjis));
+
+    //misc
+    audmad_config->show_avg_vbr_bitrate =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_avg));
+
+    //gain control
+    text = gtk_entry_get_text(GTK_ENTRY(preamp0));
+    g_free(audmad_config->replaygain.preamp0_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp0_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp0_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp0_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp0), audmad_config->replaygain.preamp0_db);
+
+    audmad_config->replaygain.enable =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(RG_enable));
-    audmad_config.replaygain.track_mode =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(RG_track_mode));
-    audmad_config.hard_limit =
+    audmad_config->replaygain.track_mode =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(trackMode));
+
+    text = gtk_entry_get_text(GTK_ENTRY(preamp1));
+    g_free(audmad_config->replaygain.preamp1_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp1_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp1_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp1_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp1), audmad_config->replaygain.preamp1_db);
+
+    text = gtk_entry_get_text(GTK_ENTRY(preamp2));
+    g_free(audmad_config->replaygain.preamp2_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp2_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp2_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp2_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp2), audmad_config->replaygain.preamp2_db);
+
+    audmad_config->replaygain.anti_clip =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(anti_clip));
+    audmad_config->replaygain.hard_limit =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hard_limit));
-    text = gtk_entry_get_text(GTK_ENTRY(RG_default));
-    g_free(audmad_config.replaygain.default_db);
-    audmad_config.replaygain.default_db = g_strdup(text);
 
-    text = gtk_entry_get_text(GTK_ENTRY(pregain));
-    g_free(audmad_config.pregain_db);
-    audmad_config.pregain_db = g_strdup(text);
-
-    audmad_config.title_override =
+    //text
+    audmad_config->title_override =
         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override));
 
     text = gtk_entry_get_text(GTK_ENTRY(title_id3_entry));
-    g_free(audmad_config.id3_format);
-    audmad_config.id3_format = g_strdup(text);
+    g_free(audmad_config->id3_format);
+    audmad_config->id3_format = g_strdup(text);
+
+}
+
+static void
+save_config(void)
+{
+    ConfigDb *db = aud_cfg_db_open();
 
-    audmad_config_compute(&audmad_config);
+    AUDDBG("saving\n");
+
+    audmad_config_compute(audmad_config);
 
-    db = aud_cfg_db_open();
-    aud_cfg_db_set_int(db, "MAD", "http_buffer_size",
-                       audmad_config.http_buffer_size);
+    //audio
+    aud_cfg_db_set_bool(db, "MAD", "dither", audmad_config->dither);
+    aud_cfg_db_set_bool(db, "MAD", "force_reopen_audio",
+                            audmad_config->force_reopen_audio);
+    //metadata
     aud_cfg_db_set_bool(db, "MAD", "fast_play_time_calc",
-                        audmad_config.fast_play_time_calc);
-    aud_cfg_db_set_bool(db, "MAD", "use_xing", audmad_config.use_xing);
-    aud_cfg_db_set_bool(db, "MAD", "dither", audmad_config.dither);
-    aud_cfg_db_set_bool(db, "MAD", "sjis", audmad_config.sjis);
-    aud_cfg_db_set_bool(db, "MAD", "hard_limit",
-                        audmad_config.hard_limit);
-    aud_cfg_db_set_string(db, "MAD", "pregain_db",
-                          audmad_config.pregain_db);
+                        audmad_config->fast_play_time_calc);
+    aud_cfg_db_set_bool(db, "MAD", "use_xing", audmad_config->use_xing);
+    aud_cfg_db_set_bool(db, "MAD", "sjis", audmad_config->sjis);
 
+    //misc
+    aud_cfg_db_set_bool(db, "MAD", "show_avg_vbr_bitrate",
+                            audmad_config->show_avg_vbr_bitrate);
+
+    //gain control
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp0_db",
+                          audmad_config->replaygain.preamp0_db);
     aud_cfg_db_set_bool(db, "MAD", "RG.enable",
-                        audmad_config.replaygain.enable);
+                        audmad_config->replaygain.enable);
     aud_cfg_db_set_bool(db, "MAD", "RG.track_mode",
-                        audmad_config.replaygain.track_mode);
-    aud_cfg_db_set_string(db, "MAD", "RG.default_db",
-                          audmad_config.replaygain.default_db);
+                        audmad_config->replaygain.track_mode);
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp1_db",
+                          audmad_config->replaygain.preamp1_db);
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp2_db",
+                          audmad_config->replaygain.preamp2_db);
+    aud_cfg_db_set_bool(db, "MAD", "RG.anti_clip",
+                        audmad_config->replaygain.anti_clip);
+    aud_cfg_db_set_bool(db, "MAD", "RG.hard_limit",
+                        audmad_config->replaygain.hard_limit);
 
-    aud_cfg_db_set_bool(db, "MAD", "title_override", audmad_config.title_override);
-    aud_cfg_db_set_string(db, "MAD", "id3_format", audmad_config.id3_format);
-
-    aud_cfg_db_set_bool(db, "MAD", "show_avg_vbr_bitrate",
-                            audmad_config.show_avg_vbr_bitrate);
-    aud_cfg_db_set_bool(db, "MAD", "force_reopen_audio",
-                            audmad_config.force_reopen_audio);
+    //text
+    aud_cfg_db_set_bool(db, "MAD", "title_override", audmad_config->title_override);
+    aud_cfg_db_set_string(db, "MAD", "id3_format", audmad_config->id3_format);
 
     aud_cfg_db_close(db);
+}
+
+static void
+configure_win_cancel(GtkWidget *widget, gpointer widgets)
+{
+    AUDDBG("cancel\n");
+    dispose_config(audmad_config);
+    audmad_config = oldconfig;
+    oldconfig = NULL;
+    save_config();
     gtk_widget_destroy(configure_win);
+    g_object_unref(widgets);
 }
 
-static void configure_destroy(GtkWidget * w, gpointer data)
+static void
+configure_win_ok(GtkWidget *widget, gpointer widgets)
+{
+    AUDDBG("ok\n");
+    update_config(widgets);
+    save_config();
+    gtk_widget_destroy(configure_win);
+    g_object_unref(widgets);
+    dispose_config(oldconfig);
+    oldconfig = NULL;
+}
+
+static void
+configure_destroy(GtkWidget *w, gpointer data)
 {
 }
 
 static void
-title_override_cb(GtkWidget * w, gpointer data)
+RG_enable_cb(GtkWidget *w, gpointer widgets)
 {
-    gboolean override;
-    override =
-        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override));
-    gtk_widget_set_sensitive(title_id3_box, override);
-    gtk_widget_set_sensitive(title_tag_desc, override);
+    GtkWidget *type_vbox = g_object_get_data(widgets, "type_vbox");
+    GtkWidget *rgtypeSet = g_object_get_data(widgets, "rgtypeSet");
+    GtkWidget *preamp1_hbox = g_object_get_data(widgets, "preamp1_hbox");
+    GtkWidget *preamp2_hbox = g_object_get_data(widgets, "preamp2_hbox");
+    GtkWidget *anti_clip = g_object_get_data(widgets, "anti_clip");
+    gboolean enabled;
+
+    update_config(widgets);
+    save_config();
+
+    enabled = audmad_config->replaygain.enable;
+
+    gtk_widget_set_sensitive(type_vbox, enabled);
+    gtk_widget_set_sensitive(rgtypeSet, enabled);
+    gtk_widget_set_sensitive(preamp1_hbox, enabled);
+    gtk_widget_set_sensitive(preamp2_hbox, enabled);
+    gtk_widget_set_sensitive(anti_clip, enabled);
+}
+
+static void
+RG_type_track_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkToggleButton *tb = GTK_TOGGLE_BUTTON(g_object_get_data(widgets, "trackMode"));
+
+    if (gtk_toggle_button_get_active(tb))
+        audmad_config->replaygain.track_mode = TRUE;
+}
+
+static void
+RG_type_album_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkToggleButton *tb = GTK_TOGGLE_BUTTON(g_object_get_data(widgets, "albumMode"));
+
+    if (gtk_toggle_button_get_active(tb))
+        audmad_config->replaygain.track_mode = FALSE;
+}
+
+static void
+simple_update_cb(GtkWidget *w, gpointer widgets)
+{
+    update_config(widgets);
+    save_config();
 }
 
-void audmad_configure(void)
+static void
+entry_changed_cb(GtkWidget *w, gpointer widgets)
+{
+    simple_update_cb(w, widgets);
+}
+
+static void
+title_override_cb(GtkWidget *w, gpointer widgets)
 {
+    GtkWidget *title_override = g_object_get_data(widgets, "title_override");
+    GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry");
+    GtkWidget *title_id3_label = g_object_get_data(widgets, "title_id3_label");
+    gboolean override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override));
+
+    update_config(widgets);
+    save_config();
+
+    gtk_widget_set_sensitive(title_id3_entry, override);
+    gtk_widget_set_sensitive(title_id3_label, override);
+}
+
+void
+audmad_configure(void)
+{
+    GtkWidget *vbox;
     GtkWidget *bbox, *ok, *cancel;
-    GtkWidget *label, *RG_default_hbox, *pregain_hbox;
-    GtkWidget *notebook, *vbox2, *title_id3_label;
+    GtkWidget *label, *preamp0_hbox, *preamp1_hbox, *preamp2_hbox;
+    GtkWidget *notebook, *vbox2, *title_id3_label, *title_id3_box;
+
+    GtkWidget *fast_playback, *use_xing, *dither, *sjis, *show_avg, *reopen;
+    GtkWidget *RG_enable, *type_vbox, *rg_vbox, *preamp0, *preamp1, *preamp2;
+    GtkWidget *trackMode, *albumMode, *hard_limit, *anti_clip;
+    GtkWidget *title_override, *title_id3_entry;
+    GtkWidget *rgtypeFrame, *replaygainFrame, *metadataFrame, *audioFrame, *miscFrame;
+    GtkWidget *metadata_vbox, *audio_vbox, *misc_vbox;
 
-    if (configure_win != NULL)
-    {
+    gpointer widgets = g_object_new(G_TYPE_OBJECT, NULL);
+
+    if(oldconfig) {
+        dispose_config(oldconfig);
+        oldconfig = NULL;
+    }
+
+    oldconfig = duplicate_config(audmad_config); //for undo
+
+    if (configure_win != NULL) {
         gtk_widget_show(configure_win);
         return;
     }
@@ -138,8 +324,7 @@
     gtk_window_set_type_hint(GTK_WINDOW(configure_win), GDK_WINDOW_TYPE_HINT_DIALOG);
 
     g_signal_connect(G_OBJECT(configure_win), "destroy",
-                       G_CALLBACK(gtk_widget_destroyed),
-                       &configure_win);
+                       G_CALLBACK(gtk_widget_destroyed), &configure_win);
     g_signal_connect(G_OBJECT(configure_win), "destroy",
                        G_CALLBACK(configure_destroy), &configure_win);
 
@@ -152,112 +337,266 @@
     gtk_container_add(GTK_CONTAINER(configure_win), vbox);
 
     notebook = gtk_notebook_new();
-    gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-    vbox2 = gtk_vbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox), notebook, FALSE, FALSE, 0);
 
-    dither = gtk_check_button_new_with_label
-        (_("Dither output when rounding to 16-bit"));
-    gtk_box_pack_start(GTK_BOX(vbox2), dither, TRUE, TRUE, 0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dither),
-                                 audmad_config.dither);
-
-    fast_playback =
-        gtk_check_button_new_with_label(_("Enable fast play-length calculation"));
-    gtk_box_pack_start(GTK_BOX(vbox2), 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(vbox2), use_xing, TRUE, TRUE, 0);
-    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);
+    /********************************************************************************/
 
-    show_avg = gtk_check_button_new_with_label(_("Display average bitrate for VBR"));
-    gtk_box_pack_start(GTK_BOX(vbox2), show_avg, TRUE, TRUE, 0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_avg),
-                                 audmad_config.show_avg_vbr_bitrate);
-
-    reopen = gtk_check_button_new_with_label(_("Force reopen audio when audio type changed"));
-    gtk_box_pack_start(GTK_BOX(vbox2), reopen, TRUE, TRUE, 0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reopen),
-                                 audmad_config.force_reopen_audio);
-
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("General")));
 
     vbox2 = gtk_vbox_new(FALSE, 5);
 
-    /* SKR added config : */
+    // audio frame
+    audioFrame = gtk_frame_new(_("Audio Settings"));
+    gtk_container_border_width(GTK_CONTAINER(audioFrame), 5);
+
+    audio_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(audioFrame), audio_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), audioFrame);
+
+    dither = gtk_check_button_new_with_label
+        (_("Dither output when rounding to 16-bit"));
+    g_object_set_data(widgets, "dither", dither);
+    gtk_box_pack_start(GTK_BOX(audio_vbox), dither, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dither),
+                                 audmad_config->dither);
+    g_signal_connect(G_OBJECT(dither), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    reopen = gtk_check_button_new_with_label(_("Force reopen audio when audio type changed"));
+    g_object_set_data(widgets, "reopen", reopen);
+    gtk_box_pack_start(GTK_BOX(audio_vbox), reopen, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reopen),
+                                 audmad_config->force_reopen_audio);
+    g_signal_connect(G_OBJECT(reopen), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+
+    // metadata frame
+    metadataFrame = gtk_frame_new(_("Metadata Settings"));
+    gtk_container_border_width(GTK_CONTAINER(metadataFrame), 5);
+
+    metadata_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(metadataFrame), metadata_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), metadataFrame);
+
+    fast_playback =
+        gtk_check_button_new_with_label(_("Enable fast play-length calculation"));
+    g_object_set_data(widgets, "fast_playback", fast_playback);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), fast_playback, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fast_playback),
+                                 audmad_config->fast_play_time_calc);
+    g_signal_connect(G_OBJECT(fast_playback), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    use_xing = gtk_check_button_new_with_label(_("Parse XING headers"));
+    g_object_set_data(widgets, "use_xing", use_xing);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), use_xing, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_xing),
+                                 audmad_config->use_xing);
+    g_signal_connect(G_OBJECT(use_xing), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    sjis = gtk_check_button_new_with_label(_("Use SJIS to write ID3 tags (not recommended)"));
+    g_object_set_data(widgets, "sjis", sjis);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), sjis, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sjis), audmad_config->sjis);
+    g_signal_connect(G_OBJECT(sjis), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    // misc frame
+    miscFrame = gtk_frame_new(_("Miscellaneous Settings"));
+    gtk_container_border_width(GTK_CONTAINER(miscFrame), 5);
+
+    misc_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(miscFrame), misc_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), miscFrame);
+
+
+    show_avg = gtk_check_button_new_with_label(_("Display average bitrate for VBR"));
+    g_object_set_data(widgets, "show_avg", show_avg);
+    gtk_box_pack_start(GTK_BOX(misc_vbox), show_avg, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_avg),
+                                 audmad_config->show_avg_vbr_bitrate);
+    g_signal_connect(G_OBJECT(show_avg), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    // add to notebook
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("General")));
+
+
+
+    /*********************************************************************************/
+
+
+    vbox2 = gtk_vbox_new(FALSE, 10);
+    gtk_container_border_width(GTK_CONTAINER(vbox2), 5);
+
+    // overall preamp
+    label = gtk_label_new(_("Base gain (dB):"));
+    preamp0_hbox = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox2), preamp0_hbox, TRUE, TRUE, 0);
+
+    preamp0 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp0", preamp0);
+    gtk_widget_set_usize(preamp0, 80, -1);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp0), audmad_config->replaygain.preamp0_db);
+    gtk_box_pack_start(GTK_BOX(preamp0_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp0_hbox), preamp0, FALSE, TRUE, 0);
+    g_signal_connect(preamp0, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+    // replaygain frame
+    replaygainFrame = gtk_frame_new(_("ReplayGain Settings"));
+    gtk_container_border_width(GTK_CONTAINER(replaygainFrame), 5);
+    g_object_set_data(widgets, "replaygainFrame", replaygainFrame);    
+
+    rg_vbox = gtk_vbox_new(FALSE, 5);
+    g_object_set_data(widgets, "rg_vbox", rg_vbox);
+    gtk_container_add(GTK_CONTAINER(replaygainFrame), rg_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), replaygainFrame);
+
+
+    // enable/disable replaygain
     RG_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
-    gtk_box_pack_start(GTK_BOX(vbox2), RG_enable, TRUE, TRUE, 0);
+    g_object_set_data(widgets, "RG_enable", RG_enable);
+    gtk_box_pack_start(GTK_BOX(rg_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(_("Track mode"));
-    gtk_box_pack_start(GTK_BOX(vbox2), RG_track_mode, TRUE, TRUE, 0);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RG_track_mode),
-                                 audmad_config.replaygain.track_mode);
+                                 audmad_config->replaygain.enable);
+
+    g_signal_connect(G_OBJECT(RG_enable), "clicked", G_CALLBACK(RG_enable_cb), widgets);
+
+
+    // replaygin type radio button
+    rgtypeFrame = gtk_frame_new(_("ReplayGain Type"));
+    g_object_set_data(widgets, "rgtypeFrame", rgtypeFrame);
+
+    type_vbox = gtk_vbox_new(FALSE, 5);
+    g_object_set_data(widgets, "type_vbox", type_vbox);
+
+    gtk_container_set_border_width(GTK_CONTAINER(type_vbox), 5);
+    gtk_container_add(GTK_CONTAINER(rgtypeFrame), type_vbox);
+    gtk_container_add(GTK_CONTAINER(rg_vbox), rgtypeFrame);
+
+    trackMode = gtk_radio_button_new_with_label(NULL, _("Use Track Gain"));
+    g_object_set_data(widgets, "trackMode", trackMode);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(trackMode), audmad_config->replaygain.track_mode);
+    gtk_box_pack_start(GTK_BOX(type_vbox), trackMode, FALSE, FALSE, 0);
+
+
+    albumMode =
+        gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(trackMode)),
+                                        _("Use Album Gain"));
+    g_object_set_data(widgets, "albumMode", albumMode);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(albumMode), !audmad_config->replaygain.track_mode);
+    gtk_box_pack_start(GTK_BOX(type_vbox), albumMode, FALSE, FALSE, 0);
+
+    // xxx 
+    g_signal_connect(G_OBJECT(trackMode), "toggled", G_CALLBACK(RG_type_track_cb), widgets);
+    g_signal_connect(G_OBJECT(albumMode), "toggled", G_CALLBACK(RG_type_album_cb), widgets);
+
+
+
+    // preamp for the files with RG info
+    label = gtk_label_new(_("Pre-gain with RG info (dB):"));
+    preamp1_hbox = gtk_hbox_new(FALSE, 5);
+    g_object_set_data(widgets, "preamp1_hbox", preamp1_hbox);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), preamp1_hbox, TRUE, TRUE, 0);
 
-    hard_limit =
-        gtk_check_button_new_with_label
-        (_("6dB hard limiting"));
+    preamp1 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp1", preamp1);
+    gtk_widget_set_usize(preamp1, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(preamp1),
+                       audmad_config->replaygain.preamp1_db);
+    gtk_box_pack_start(GTK_BOX(preamp1_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp1_hbox), preamp1, FALSE, TRUE, 0);
+    g_signal_connect(preamp1, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+
+    // preamp for the files without RG info
+    label = gtk_label_new(_("Pre-gain without RG info (dB):"));
+    preamp2_hbox = gtk_hbox_new(FALSE, 5);
+    g_object_set_data(widgets, "preamp2_hbox", preamp2_hbox);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), preamp2_hbox, TRUE, TRUE, 0);
+
+    preamp2 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp2", preamp2);
+    gtk_widget_set_usize(preamp2, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(preamp2),
+                       audmad_config->replaygain.preamp2_db);
+    gtk_box_pack_start(GTK_BOX(preamp2_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp2_hbox), preamp2, FALSE, TRUE, 0);
+    g_signal_connect(preamp2, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+
+    // clipping prevention
+    anti_clip = gtk_check_button_new_with_label(_("Enable clip prevention using peak info"));
+    g_object_set_data(widgets, "anti_clip", anti_clip);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), anti_clip, TRUE, TRUE, 0);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(anti_clip),
+                                 audmad_config->replaygain.anti_clip);
+
+    g_signal_connect(G_OBJECT(anti_clip), "clicked",
+                     G_CALLBACK(simple_update_cb), widgets);
+
+    // sensitivity
+    if(!audmad_config->replaygain.enable) {
+        gtk_widget_set_sensitive(type_vbox, FALSE);
+        gtk_widget_set_sensitive(rgtypeFrame, FALSE);
+        gtk_widget_set_sensitive(preamp1_hbox, FALSE);
+        gtk_widget_set_sensitive(preamp2_hbox, FALSE);
+        gtk_widget_set_sensitive(anti_clip, FALSE);
+    }
+    /* end of replaygainFrame */
+
+
+    // 6dB hard limit
+    hard_limit = gtk_check_button_new_with_label(_("Apply 6dB hard limit"));
+    g_object_set_data(widgets, "hard_limit", hard_limit);
     gtk_box_pack_start(GTK_BOX(vbox2), hard_limit, TRUE, TRUE, 0);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hard_limit),
-                                 audmad_config.hard_limit);
+                                 audmad_config->replaygain.hard_limit);
+
+    g_signal_connect(G_OBJECT(hard_limit), "clicked",
+                     G_CALLBACK(simple_update_cb), widgets);
+
 
-    label = gtk_label_new(_("Default gain (dB):"));
-    RG_default_hbox = gtk_hbox_new(FALSE, 5);
-    gtk_box_pack_start(GTK_BOX(vbox2), 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);
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("Gain Control")));
+
 
-    label = gtk_label_new(_("Preamp (dB):"));
-    pregain_hbox = gtk_hbox_new(FALSE, 5);
-    gtk_box_pack_start(GTK_BOX(vbox2), 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);
+    /*********************************************************************************/
 
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("ReplayGain")));
 
     vbox2 = gtk_vbox_new(FALSE, 5);
 
-    title_override =
-        gtk_check_button_new_with_label(_("Override generic titles"));
+    title_override = gtk_check_button_new_with_label(_("Override generic titles"));
+    g_object_set_data(widgets, "title_override", title_override);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_override),
-                                 audmad_config.title_override);
-    g_signal_connect(G_OBJECT(title_override), "clicked",
-                     G_CALLBACK(title_override_cb), NULL);
+                                 audmad_config->title_override);
     gtk_box_pack_start(GTK_BOX(vbox2), title_override, FALSE,
                        FALSE, 0);
+    g_signal_connect(G_OBJECT(title_override), "clicked",
+                     G_CALLBACK(title_override_cb), widgets);
 
     title_id3_box = gtk_hbox_new(FALSE, 5);
-    gtk_widget_set_sensitive(title_id3_box, audmad_config.title_override);
-    gtk_box_pack_start(GTK_BOX(vbox2), title_id3_box, FALSE,
-                       FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox2), title_id3_box, FALSE, FALSE, 0);
 
     title_id3_label = gtk_label_new(_("ID3 format:"));
-    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_label, FALSE,
-                       FALSE, 0);
+    g_object_set_data(widgets, "title_id3_label", title_id3_label);
+    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_label, FALSE, FALSE, 0);
+    gtk_widget_set_sensitive(title_id3_label, audmad_config->title_override);
 
     title_id3_entry = gtk_entry_new();
-    gtk_entry_set_text(GTK_ENTRY(title_id3_entry), audmad_config.id3_format);
-    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_entry, TRUE, TRUE,
-                       0);
+    g_object_set_data(widgets, "title_id3_entry", title_id3_entry);
+    gtk_entry_set_text(GTK_ENTRY(title_id3_entry), audmad_config->id3_format);
+    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_entry, TRUE, TRUE, 0);
+    g_signal_connect(title_id3_entry, "changed", G_CALLBACK(entry_changed_cb), widgets);
+    gtk_widget_set_sensitive(title_id3_entry, audmad_config->title_override);
 
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2,
-                             gtk_label_new(_("Title")));
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("Title")));
+
+
+
+    /*********************************************************************************/
+
 
     bbox = gtk_hbutton_box_new();
     gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
@@ -265,14 +604,17 @@
     gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
 
     cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
-    g_signal_connect_swapped(G_OBJECT(cancel), "clicked",
-                              G_CALLBACK(gtk_widget_destroy),
-                              G_OBJECT(configure_win));
+
+    g_signal_connect(G_OBJECT(cancel), "clicked",
+                     G_CALLBACK(configure_win_cancel), widgets);
+
     gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
 
     ok = gtk_button_new_from_stock(GTK_STOCK_OK);
+
     g_signal_connect(G_OBJECT(ok), "clicked",
-                       G_CALLBACK(configure_win_ok), NULL);
+                     G_CALLBACK(configure_win_ok), widgets);
+
     gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
     gtk_widget_grab_default(ok);
 
--- a/src/madplug/decoder.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/decoder.c	Thu Jan 31 15:22:15 2008 +0900
@@ -19,6 +19,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define AUD_DEBUG 1 */
+
 #include <math.h>
 #include <assert.h>
 #include <pthread.h>
@@ -42,27 +44,55 @@
 static inline signed int
 scale(mad_fixed_t sample, struct mad_info_t *file_info)
 {
-    /* replayGain by SamKR */
     gdouble scale = -1;
-    if (audmad_config.replaygain.enable) {
+    static int i = 0;
+
+    if (audmad_config->replaygain.enable) {
         if (file_info->has_replaygain) {
-            scale = file_info->replaygain_track_scale;
-            if (file_info->replaygain_album_scale != -1
-                && (scale == -1 || !audmad_config.replaygain.track_mode))
-            {
+            // apply track gain if it is available and track mode is specified
+            if(file_info->replaygain_track_scale != -1) {
+                scale = file_info->replaygain_track_scale;
+            }
+            // apply album gain if available
+            if(!audmad_config->replaygain.track_mode &&
+               file_info->replaygain_album_scale != -1) {
                 scale = file_info->replaygain_album_scale;
             }
+
+            // apply preamp1
+            scale *= audmad_config->replaygain.preamp1_scale;
+
+            if (audmad_config->replaygain.anti_clip) {
+                if(i%100000 == 0)
+                    AUDDBG("track_peak = %f\n", file_info->replaygain_track_peak);
+                if(scale * file_info->replaygain_track_peak >= 1.0)
+                    scale = 1.0 / file_info->replaygain_track_peak;
+            }
         }
-        if (scale == -1)
-            scale = audmad_config.replaygain.default_scale;
+        else {
+            // apply preamp2 for files without RG info
+            scale = audmad_config->replaygain.preamp2_scale;
+        }
+    }
+    else {
+        scale = 1.0;
     }
-    if (scale == -1)
-        scale = 1.0;
-    if (audmad_config.pregain_scale != 1)
-        scale = scale * audmad_config.pregain_scale;
+
+    // apply global gain
+    if (audmad_config->replaygain.preamp0_scale != 1)
+        scale = scale * audmad_config->replaygain.preamp0_scale;
+
+    if(i%100000 == 0) {
+        AUDDBG("scale = %f\n", scale);
+    }
 
     /* hard-limit (clipping-prevention) */
-    if (audmad_config.hard_limit) {
+    if (audmad_config->replaygain.hard_limit) {
+
+        if(i%100000 == 0) {
+            AUDDBG("hard_limit\n");
+        }
+
         /* convert to double before computation, to avoid mad_fixed_t wrapping */
         double x = mad_f_todouble(sample) * scale;
         static const double k = 0.5;    // -6dBFS
@@ -73,10 +103,17 @@
             x = tanh((x + k) / (1 - k)) * (1 - k) - k;
         }
         sample = x * (MAD_F_ONE);
+
+        if(i%100000 == 0) {
+            AUDDBG("x = %f sample = %d\n", x, sample);
+        }
+
     }
     else
         sample *= scale;
 
+    i++;
+
     int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
 
     /* round */
@@ -88,7 +125,7 @@
 #endif
 
     /* dither one bit of actual output */
-    if (audmad_config.dither) {
+    if (audmad_config->dither) {
         int dither = triangular_dither_noise(n_bits_to_loose + 1);
         sample += dither;
     }
@@ -166,7 +203,8 @@
  * Decode all headers in the file and fill in stats
  * @return FALSE if scan failed.
  */
-gboolean scan_file(struct mad_info_t * info, gboolean fast)
+gboolean
+scan_file(struct mad_info_t * info, gboolean fast)
 {
     struct mad_stream stream;
     struct mad_header header;
@@ -277,7 +315,7 @@
                 info->mpeg_layer = header.layer;
                 info->mode = header.mode;
 
-                if (audmad_config.use_xing) {
+                if (audmad_config->use_xing) {
                     frame.header = header;
                     if (mad_frame_decode(&frame, &stream) == -1) {
                         AUDDBG("xing frame decode failed\n");
@@ -401,7 +439,8 @@
 }
 
 /* sanity check for audio open parameters */
-static gboolean check_audio_param(struct mad_info_t *info)
+static gboolean
+check_audio_param(struct mad_info_t *info)
 {
     if(info->fmt < FMT_U8 || info->fmt > FMT_S16_NE)
         return FALSE;
@@ -413,7 +452,8 @@
     return TRUE;
 }
 
-gpointer decode_loop(gpointer arg)
+gpointer
+decode_loop(gpointer arg)
 {
     unsigned char buffer[BUFFER_SIZE];
     int len;
@@ -461,8 +501,8 @@
     /* set mainwin title */
     if (info->title)
         g_free(info->title);
-    info->title = aud_tuple_formatter_make_title_string(info->tuple, audmad_config.title_override == TRUE ?
-                                       audmad_config.id3_format : aud_get_gentitle_format());
+    info->title = aud_tuple_formatter_make_title_string(info->tuple, audmad_config->title_override == TRUE ?
+                                       audmad_config->id3_format : aud_get_gentitle_format());
 
     tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS),
         info->playback->set_params(info->playback, info->title,
@@ -581,7 +621,7 @@
 
             info->bitrate = frame.header.bitrate;
 
-            if (!audmad_config.show_avg_vbr_bitrate && info->vbr && (iteration % 40 == 0)) {
+            if (!audmad_config->show_avg_vbr_bitrate && info->vbr && (iteration % 40 == 0)) {
 
 #ifdef DEBUG_INTENSIVELY
                 AUDDBG("decode vbr tlen = %d\n", tlen);
@@ -618,7 +658,7 @@
                 info->freq = frame.header.samplerate;
                 info->channels = MAD_NCHANNELS(&frame.header);
 
-                if(audmad_config.force_reopen_audio && check_audio_param(info)) {
+                if(audmad_config->force_reopen_audio && check_audio_param(info)) {
                     gint current_time = info->playback->output->output_time();
 
                     AUDDBG("re-opening audio due to change in audio type\n");
--- a/src/madplug/dither.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/dither.c	Thu Jan 31 15:22:15 2008 +0900
@@ -14,7 +14,8 @@
 #include "SFMT.h"
 #include "SFMT.c"
 
-int triangular_dither_noise(int nbits)
+int
+triangular_dither_noise(int nbits)
 {
     // parameter nbits : the peak-to-peak amplitude desired (in bits)
     //  use with nbits set to    2 + nber of bits to be trimmed.
--- a/src/madplug/input.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/input.c	Thu Jan 31 15:22:15 2008 +0900
@@ -69,7 +69,8 @@
 /**
  * init the mad_info_t struct.
  */
-gboolean input_init(struct mad_info_t * info, const char *url, VFSFile *fd)
+gboolean
+input_init(struct mad_info_t * info, const char *url, VFSFile *fd)
 {
     AUDDBG("f: input_init\n");
 
@@ -119,7 +120,8 @@
 }
 
 /* return length in letters */
-size_t mad_ucs4len(id3_ucs4_t *ucs)
+size_t
+mad_ucs4len(id3_ucs4_t *ucs)
 {
     id3_ucs4_t *ptr = ucs;
     size_t len = 0;
@@ -131,7 +133,8 @@
 }
 
 /* duplicate id3_ucs4_t string. new string will be terminated with 0. */
-id3_ucs4_t *mad_ucs4dup(id3_ucs4_t *org)
+id3_ucs4_t *
+mad_ucs4dup(id3_ucs4_t *org)
 {
     id3_ucs4_t *new = NULL;
     size_t len = mad_ucs4len(org);
@@ -145,7 +148,8 @@
 
 #define BYTES(x) ((x) * sizeof(id3_ucs4_t))
 
-id3_ucs4_t *mad_parse_genre(const id3_ucs4_t *string)
+id3_ucs4_t *
+mad_parse_genre(const id3_ucs4_t *string)
 {
     id3_ucs4_t *ret = NULL;
     id3_ucs4_t *tmp = NULL;
@@ -256,7 +260,8 @@
     return ret;
 }
 
-gchar *input_id3_get_string(struct id3_tag * tag, const gchar *frame_name)
+gchar *
+input_id3_get_string(struct id3_tag * tag, const gchar *frame_name)
 {
     gchar *rtn0 = NULL, *rtn = NULL;
     const id3_ucs4_t *string_const = NULL;
@@ -316,7 +321,8 @@
     return rtn;
 }
 
-static void input_set_and_free_tag(struct id3_tag *tag, Tuple *tuple, const gchar *frame, const gint nfield)
+static void
+input_set_and_free_tag(struct id3_tag *tag, Tuple *tuple, const gchar *frame, const gint nfield)
 {
     gchar *scratch = input_id3_get_string(tag, frame);
 
@@ -326,7 +332,8 @@
     g_free(scratch);
 }
 
-static void input_alloc_tag(struct mad_info_t *info)
+static void
+input_alloc_tag(struct mad_info_t *info)
 {
     Tuple *tuple;
 
@@ -340,7 +347,8 @@
 /**
  * read the ID3 tag 
  */
-static void input_read_tag(struct mad_info_t *info)
+static void
+input_read_tag(struct mad_info_t *info)
 {
     gchar *string = NULL;
     Tuple *tuple;
@@ -411,8 +419,8 @@
     aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, "MPEG Audio (MP3)");
     aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, "lossy");
 
-    info->title = aud_tuple_formatter_make_title_string(tuple, audmad_config.title_override == TRUE ?
-        audmad_config.id3_format : aud_get_gentitle_format());
+    info->title = aud_tuple_formatter_make_title_string(tuple, audmad_config->title_override == TRUE ?
+        audmad_config->id3_format : aud_get_gentitle_format());
 
     // for connection via proxy, we have to stop transfer once. I can't explain the reason.
     if (info->infile != NULL) {
@@ -423,7 +431,8 @@
     AUDDBG("e: input_read_tag\n");
 }
 
-void input_process_remote_metadata(struct mad_info_t *info)
+void
+input_process_remote_metadata(struct mad_info_t *info)
 {
     gboolean metadata = FALSE;
 
@@ -497,7 +506,8 @@
  * Retrieve meta-information about URL.
  * For local files this means ID3 tag etc.
  */
-gboolean input_get_info(struct mad_info_t *info, gboolean fast_scan)
+gboolean
+input_get_info(struct mad_info_t *info, gboolean fast_scan)
 {
 #ifdef AUD_DEBUG
     gchar *tmp = g_filename_to_utf8(info->filename, -1, NULL, NULL, NULL);    
@@ -570,7 +580,8 @@
 /**
  * Free up all mad_info_t related resourses.
  */
-gboolean input_term(struct mad_info_t * info)
+gboolean
+input_term(struct mad_info_t * info)
 {
     AUDDBG("f: input_term\n");
 
--- a/src/madplug/plugin.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/plugin.c	Thu Jan 31 15:22:15 2008 +0900
@@ -40,7 +40,7 @@
 /*
  * Global variables
  */
-struct audmad_config_t audmad_config;   /**< global configuration */
+audmad_config_t *audmad_config;   /**< global configuration */
 GMutex *mad_mutex;
 GMutex *pb_mutex;
 GCond *mad_cond;
@@ -79,7 +79,8 @@
  *    filename has no extension.
  *
  */
-static gchar *extname(const char *filename)
+static gchar *
+extname(const char *filename)
 {
     gchar *ext = strrchr(filename, '.');
 
@@ -90,7 +91,8 @@
 }
 
 
-void audmad_config_compute(struct audmad_config_t *config)
+void
+audmad_config_compute(audmad_config_t *config)
 {
     /* set some config parameters by parsing text fields
        (RG default gain, etc..)
@@ -98,64 +100,92 @@
     const gchar *text;
     gdouble x;
 
-    text = config->pregain_db;
+    text = config->replaygain.preamp0_db;
     if ( text != NULL )
       x = g_strtod(text, NULL);
     else
       x = 0;
-    config->pregain_scale = (x != 0) ? pow(10.0, x / 20) : 1;
-    AUDDBG("pregain=[%s] -> %g  -> %g\n", text, x, config->pregain_scale);
-    text = config->replaygain.default_db;
+    config->replaygain.preamp0_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp0=[%s] -> %g  -> %g\n", text, x, config->preamp0_scale);
+
+    text = config->replaygain.preamp1_db;
+    if ( text != NULL )
+      x = g_strtod(text, NULL);
+    else
+      x = 0;
+    config->replaygain.preamp1_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp1=[%s] -> %g  -> %g\n", text, x,
+              config->replaygain.preamp1_scale);
+
+    text = config->replaygain.preamp2_db;
     if ( text != NULL )
       x = g_strtod(text, NULL);
     else
       x = 0;
-    config->replaygain.default_scale = (x != 0) ? pow(10.0, x / 20) : 1;
-    AUDDBG("RG.default=[%s] -> %g  -> %g\n", text, x,
-              config->replaygain.default_scale);
+    config->replaygain.preamp2_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp2=[%s] -> %g  -> %g\n", text, x,
+              config->replaygain.preamp2_scale);
 }
 
-static void audmad_init()
+static void
+audmad_init()
 {
     ConfigDb *db = NULL;
 
-    audmad_config.fast_play_time_calc = TRUE;
-    audmad_config.use_xing = TRUE;
-    audmad_config.dither = TRUE;
-    audmad_config.sjis = FALSE;
-    audmad_config.hard_limit = FALSE;
-    audmad_config.replaygain.enable = TRUE;
-    audmad_config.replaygain.track_mode = FALSE;
-    audmad_config.title_override = FALSE;
-    audmad_config.show_avg_vbr_bitrate = TRUE;
-    audmad_config.force_reopen_audio = FALSE;
+    audmad_config = g_malloc0(sizeof(audmad_config_t));
+
+    audmad_config->dither = TRUE;
+    audmad_config->force_reopen_audio = FALSE;
+    audmad_config->fast_play_time_calc = TRUE;
+    audmad_config->use_xing = TRUE;
+    audmad_config->sjis = FALSE;
+    audmad_config->show_avg_vbr_bitrate = TRUE;
+    audmad_config->replaygain.enable = TRUE;
+    audmad_config->replaygain.track_mode = FALSE;
+    audmad_config->replaygain.anti_clip = FALSE;
+    audmad_config->replaygain.hard_limit = FALSE;
+    audmad_config->title_override = FALSE;
+
 
     db = aud_cfg_db_open();
     if (db) {
+        //audio
+        aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config->dither);
+        aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio",
+                            &audmad_config->force_reopen_audio);
+
+        //metadata
         aud_cfg_db_get_bool(db, "MAD", "fast_play_time_calc",
-                            &audmad_config.fast_play_time_calc);
+                            &audmad_config->fast_play_time_calc);
         aud_cfg_db_get_bool(db, "MAD", "use_xing",
-                            &audmad_config.use_xing);
-        aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config.dither);
-        aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config.sjis);
-        aud_cfg_db_get_bool(db, "MAD", "hard_limit",
-                            &audmad_config.hard_limit);
-        aud_cfg_db_get_string(db, "MAD", "pregain_db",
-                              &audmad_config.pregain_db);
+                            &audmad_config->use_xing);
+        aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config->sjis);
+
+        //misc
+        aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate",
+                            &audmad_config->show_avg_vbr_bitrate);
+
+        //gain control
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp0_db",
+                              &audmad_config->replaygain.preamp0_db);
         aud_cfg_db_get_bool(db, "MAD", "RG.enable",
-                            &audmad_config.replaygain.enable);
+                            &audmad_config->replaygain.enable);
         aud_cfg_db_get_bool(db, "MAD", "RG.track_mode",
-                            &audmad_config.replaygain.track_mode);
-        aud_cfg_db_get_string(db, "MAD", "RG.default_db",
-                              &audmad_config.replaygain.default_db);
+                            &audmad_config->replaygain.track_mode);
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp1_db",
+                              &audmad_config->replaygain.preamp1_db);
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp2_db",
+                              &audmad_config->replaygain.preamp2_db);
+        aud_cfg_db_get_bool(db, "MAD", "RG.anti_clip",
+                            &audmad_config->replaygain.anti_clip);
+        aud_cfg_db_get_bool(db, "MAD", "RG.hard_limit",
+                            &audmad_config->replaygain.hard_limit);
+
+        //text
         aud_cfg_db_get_bool(db, "MAD", "title_override",
-                            &audmad_config.title_override);
+                            &audmad_config->title_override);
         aud_cfg_db_get_string(db, "MAD", "id3_format",
-                              &audmad_config.id3_format);
-        aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate",
-                            &audmad_config.show_avg_vbr_bitrate);
-        aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio",
-                            &audmad_config.force_reopen_audio);
+                              &audmad_config->id3_format);
 
         aud_cfg_db_close(db);
     }
@@ -163,38 +193,40 @@
     mad_mutex = g_mutex_new();
     pb_mutex = g_mutex_new();
     mad_cond = g_cond_new();
-    audmad_config_compute(&audmad_config);
+    audmad_config_compute(audmad_config);
 
-    if (!audmad_config.pregain_db)
-        audmad_config.pregain_db = g_strdup("+0.00");
+    if (!audmad_config->replaygain.preamp0_db)
+        audmad_config->replaygain.preamp0_db = g_strdup("+0.00");
 
-    if (!audmad_config.replaygain.default_db)
-        audmad_config.replaygain.default_db = g_strdup("-9.00");
+    if (!audmad_config->replaygain.preamp1_db)
+        audmad_config->replaygain.preamp1_db = g_strdup("+6.00");
+    if (!audmad_config->replaygain.preamp2_db)
+        audmad_config->replaygain.preamp2_db = g_strdup("+0.00");
 
-    if (!audmad_config.id3_format)
-        audmad_config.id3_format = g_strdup("");
+    if (!audmad_config->id3_format)
+        audmad_config->id3_format = g_strdup("(none)");
 
     init_gen_rand(4357);
 
     aud_mime_set_plugin("audio/mpeg", mad_plugin);
 }
 
-static void audmad_cleanup()
+static void
+audmad_cleanup()
 {
-    g_free(audmad_config.pregain_db);
-    g_free(audmad_config.replaygain.default_db);
-    g_free(audmad_config.id3_format);
-
-    audmad_config.pregain_db = NULL;
-    audmad_config.replaygain.default_db = NULL;
-    audmad_config.id3_format = NULL;
-
+    g_free(audmad_config->replaygain.preamp0_db);
+    g_free(audmad_config->replaygain.preamp1_db);
+    g_free(audmad_config->replaygain.preamp2_db);
+    g_free(audmad_config->id3_format);
+    g_free(audmad_config);
+    
     g_cond_free(mad_cond);
     g_mutex_free(mad_mutex);
     g_mutex_free(pb_mutex);
 }
 
-static gboolean mp3_head_check(guint32 head, gint *frameSize)
+static gboolean
+mp3_head_check(guint32 head, gint *frameSize)
 {
     gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding;
 
@@ -282,7 +314,8 @@
     return TRUE;
 }
 
-static int mp3_head_convert(const guchar * hbuf)
+static int
+mp3_head_convert(const guchar * hbuf)
 {
     return ((unsigned long) hbuf[0] << 24) |
         ((unsigned long) hbuf[1] << 16) |
@@ -290,7 +323,8 @@
 }
 
 // audacious vfs fast version
-static int audmad_is_our_fd(char *filename, VFSFile *fin)
+static int
+audmad_is_our_fd(char *filename, VFSFile *fin)
 {
     guint32 check;
     gchar *ext = extname(filename);
@@ -376,7 +410,8 @@
 }
 
 // audacious vfs version
-static int audmad_is_our_file(char *filename)
+static int
+audmad_is_our_file(char *filename)
 {
     VFSFile *fin = NULL;
     gint rtn;
@@ -392,7 +427,8 @@
     return rtn;
 }
 
-static void audmad_stop(InputPlayback *playback)
+static void
+audmad_stop(InputPlayback *playback)
 {
     AUDDBG("f: audmad_stop\n");
     g_mutex_lock(mad_mutex);
@@ -417,7 +453,8 @@
     AUDDBG("e: audmad_stop\n");
 }
 
-static void audmad_play_file(InputPlayback *playback)
+static void
+audmad_play_file(InputPlayback *playback)
 {
     gboolean rtn;
     gchar *url = playback->filename;
@@ -436,7 +473,7 @@
     }
 
     // remote access must use fast scan.
-    rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config.fast_play_time_calc);
+    rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config->fast_play_time_calc);
 
     if (rtn == FALSE) {
         g_message("error reading input info");
@@ -456,7 +493,8 @@
     decode_loop(&info);
 }
 
-static void audmad_pause(InputPlayback *playback, short paused)
+static void
+audmad_pause(InputPlayback *playback, short paused)
 {
     g_mutex_lock(pb_mutex);
     info.playback = playback;
@@ -464,7 +502,8 @@
     playback->output->pause(paused);
 }
 
-static void audmad_mseek(InputPlayback *playback, gulong millisecond)
+static void
+audmad_mseek(InputPlayback *playback, gulong millisecond)
 {
     g_mutex_lock(pb_mutex);
     info.playback = playback;
@@ -472,7 +511,8 @@
     g_mutex_unlock(pb_mutex);
 }
 
-static void audmad_seek(InputPlayback *playback, gint time)
+static void
+audmad_seek(InputPlayback *playback, gint time)
 {
     audmad_mseek(playback, time * 1000);
 }
@@ -496,7 +536,7 @@
         return;
     }
 
-    if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config.fast_play_time_calc) == TRUE) {
+    if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config->fast_play_time_calc) == TRUE) {
         if(aud_tuple_get_string(myinfo.tuple, -1, "track-name"))
             *title = g_strdup(aud_tuple_get_string(myinfo.tuple, -1, "track-name"));
         else
@@ -526,10 +566,11 @@
     }
     
     info->fileinfo_request = FALSE; /* we don't need to read tuple again */
-    return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config.fast_play_time_calc);
+    return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config->fast_play_time_calc);
 }
 
-static void audmad_about()
+static void
+audmad_about()
 {
     static GtkWidget *aboutbox;
     gchar *scratch;
@@ -568,7 +609,8 @@
  * Display a GTK box containing the given error message.
  * Taken from mpg123 plugin.
  */
-void audmad_error(char *error, ...)
+void
+audmad_error(char *error, ...)
 {
 #ifndef NOGUI
     if (!error_dialog) {
@@ -590,14 +632,16 @@
 
 extern void audmad_configure();
 
-static void __set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value)
+static void
+__set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value)
 {
     aud_tuple_associate_string(tuple, nfield, name, value);
     g_free(value);
 }
 
 // tuple stuff
-static Tuple *__audmad_get_song_tuple(char *filename, VFSFile *fd)
+static Tuple *
+__audmad_get_song_tuple(char *filename, VFSFile *fd)
 {
     Tuple *tuple = NULL;
     gchar *string = NULL;
@@ -749,12 +793,14 @@
     return tuple;
 }
 
-static Tuple *audmad_get_song_tuple(char *filename)
+static Tuple *
+audmad_get_song_tuple(char *filename)
 {
     return __audmad_get_song_tuple(filename, NULL);
 }
 
-static Tuple *audmad_probe_for_tuple(char *filename, VFSFile *fd)
+static Tuple *
+audmad_probe_for_tuple(char *filename, VFSFile *fd)
 {
     if (!audmad_is_our_fd(filename, fd))
         return NULL;
--- a/src/madplug/plugin.h	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/plugin.h	Thu Jan 31 15:22:15 2008 +0900
@@ -103,32 +103,36 @@
 
 };
 
-struct audmad_config_t
+typedef struct audmad_config_t
 {
-    gint http_buffer_size;
     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)
+
     struct
     {
+        gchar *preamp0_db;          // gain applied to samples at decoding stage.
+        gdouble preamp0_scale;      // pow(10, pregain/20)
         gboolean enable;
         gboolean track_mode;
-        gchar *default_db;      // gain used if no RG.
-        gdouble default_scale;
+        gchar *preamp1_db;      // preamp used with RG info.
+        gdouble preamp1_scale;
+        gchar *preamp2_db;      // preamp used without RG info.
+        gdouble preamp2_scale;
+        gboolean hard_limit;
+        gboolean anti_clip;
     } replaygain;
+
     gboolean title_override;
     gchar *id3_format;
     gboolean show_avg_vbr_bitrate;
     gboolean force_reopen_audio;
-};
+} audmad_config_t;
 
 // global variables
 extern InputPlugin *mad_plugin;
-extern struct audmad_config_t audmad_config;
+extern audmad_config_t *audmad_config;
 
 // gcond
 extern GMutex *mad_mutex;
--- a/src/madplug/replaygain.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/replaygain.c	Thu Jan 31 15:22:15 2008 +0900
@@ -27,14 +27,16 @@
 #include <assert.h>
 #include "replaygain.h"
 
-static unsigned long Read_LE_Uint32(const unsigned char *p)
+static unsigned long
+Read_LE_Uint32(const unsigned char *p)
 {
     return ((unsigned long) p[0] << 0) |
         ((unsigned long) p[1] << 8) |
         ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24);
 }
 
-static int uncase_strcmp(const char *s1, const char *s2)
+static int
+uncase_strcmp(const char *s1, const char *s2)
 {
     int l1 = strlen(s1);
     int l2 = strlen(s2);
@@ -48,7 +50,8 @@
     return (l1 < l2) ? -1 : +1;
 }
 
-static gdouble strgain2double(gchar * s, int len)
+static gdouble
+strgain2double(gchar * s, int len)
 {
     gdouble res = g_strtod(s, NULL);    // gain, in dB.
     if (res == 0)
@@ -58,7 +61,8 @@
 
 // Reads APE v2.0 tag ending at current pos in fp
 
-static int ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file_info)
+static int
+ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file_info)
 {
     unsigned long vsize;
     unsigned long isize;
@@ -164,7 +168,8 @@
     return 0;
 }
 
-static int find_offset(VFSFile * fp)
+static int
+find_offset(VFSFile * fp)
 {
     static const char *key = "APETAGEX";
     char buff[20000];
@@ -196,7 +201,8 @@
 /* Eugene Zagidullin:
  * Read ReplayGain info from foobar2000-style id3v2 frames */
 
-static int ReadId3v2TXXX(struct mad_info_t *file_info)
+static int
+ReadId3v2TXXX(struct mad_info_t *file_info)
 {
 	int i;
 	char *key;
@@ -250,7 +256,8 @@
 	return 0;
 }
 
-void read_replaygain(struct mad_info_t *file_info)
+void
+read_replaygain(struct mad_info_t *file_info)
 {
     VFSFile *fp;
     glong curpos = 0;
@@ -264,10 +271,10 @@
     file_info->mp3gain_minmax = -77;
 
     if (ReadId3v2TXXX(file_info)) {
+        AUDDBG("found ReplayGain info in id3v2 tag\n");
 #ifdef AUD_DEBUG
-        AUDDBG("found ReplayGain info in id3v2 tag\n");
+	gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL);
 
-	gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL);
         AUDDBG("RG album scale= %g, RG track scale = %g, in %s\n",
 		  file_info->replaygain_album_scale,
 		  file_info->replaygain_track_scale, tmp);
@@ -316,10 +323,8 @@
                      offs, res);
             }
         }
-#ifdef AUD_DEBUG
         else 
             AUDDBG("replaygain: not found\n");
-#endif
     }
 #ifdef AUD_DEBUG
     if (res == 0) {             // got APE tags, show the result
--- a/src/madplug/tuple.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/tuple.c	Thu Jan 31 15:22:15 2008 +0900
@@ -161,13 +161,13 @@
 
     id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);    /* enables id3v1. TODO: make id3v1 optional */
     
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TITLE, tuple, FIELD_TITLE, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ARTIST, tuple, FIELD_ARTIST, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ALBUM, tuple, FIELD_ALBUM, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_YEAR, tuple, FIELD_YEAR, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_COMMENT, tuple, FIELD_COMMENT, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TRACK, tuple, FIELD_TRACK_NUMBER, audmad_config.sjis);
-    update_id3_frame_from_tuple(id3tag, ID3_FRAME_GENRE, tuple, FIELD_GENRE, audmad_config.sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TITLE, tuple, FIELD_TITLE, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ARTIST, tuple, FIELD_ARTIST, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ALBUM, tuple, FIELD_ALBUM, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_YEAR, tuple, FIELD_YEAR, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_COMMENT, tuple, FIELD_COMMENT, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TRACK, tuple, FIELD_TRACK_NUMBER, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_GENRE, tuple, FIELD_GENRE, audmad_config->sjis);
 
     if(!id3_tag_findframe(id3tag, "TLEN", 0) && input_init(&songinfo, fd->uri, fd) && !songinfo.remote) {
         AUDDBG("update TLEN frame\n");
--- a/src/madplug/xing.c	Wed Jan 30 05:04:15 2008 +0300
+++ b/src/madplug/xing.c	Thu Jan 31 15:22:15 2008 +0900
@@ -29,7 +29,8 @@
  * NAME:	xing->init()
  * DESCRIPTION:	initialize Xing structure
  */
-void xing_init(struct xing *xing)
+void
+xing_init(struct xing *xing)
 {
     xing->flags = 0;
     xing->frames = 0;
@@ -42,7 +43,8 @@
  * NAME:	xing->parse()
  * DESCRIPTION:	parse a Xing VBR header
  */
-int xing_parse(struct xing *xing, struct mad_bitptr ptr,
+int
+xing_parse(struct xing *xing, struct mad_bitptr ptr,
                unsigned int bitlen)
 {
     if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)