changeset 103:117bc56d906b trunk

[svn] flac -> flac113
author nenolod
date Mon, 23 Oct 2006 19:51:39 -0700
parents aff1cf3e86dd
children 4b31176c198a
files ChangeLog src/flac/Makefile src/flac/charset.c src/flac/charset.h src/flac/configure.c src/flac/configure.h src/flac/fast_float_math_hack.h src/flac/file.c src/flac/fileinfo.c src/flac/grabbag.h src/flac/grabbag/cuesheet.h src/flac/grabbag/file.h src/flac/grabbag/replaygain.h src/flac/grabbag/seektable.h src/flac/http.c src/flac/http.h src/flac/plugin.c src/flac/plugin.h src/flac/plugin_common/Makefile src/flac/plugin_common/all.h src/flac/plugin_common/charset.c src/flac/plugin_common/charset.h src/flac/plugin_common/defs.h src/flac/plugin_common/dither.c src/flac/plugin_common/dither.h src/flac/plugin_common/locale_hack.h src/flac/plugin_common/replaygain.c src/flac/plugin_common/replaygain.h src/flac/plugin_common/tags.c src/flac/plugin_common/tags.h src/flac/replaygain.c src/flac/replaygain_analysis.c src/flac/replaygain_analysis.h src/flac/replaygain_synthesis.c src/flac/replaygain_synthesis.h src/flac/tag.c src/flac/tag.h src/flac113/Makefile src/flac113/charset.c src/flac113/charset.h src/flac113/configure.c src/flac113/configure.h src/flac113/fast_float_math_hack.h src/flac113/file.c src/flac113/fileinfo.c src/flac113/grabbag.h src/flac113/grabbag/cuesheet.h src/flac113/grabbag/file.h src/flac113/grabbag/replaygain.h src/flac113/grabbag/seektable.h src/flac113/http.c src/flac113/http.h src/flac113/plugin.c src/flac113/plugin.h src/flac113/plugin_common/Makefile src/flac113/plugin_common/all.h src/flac113/plugin_common/charset.c src/flac113/plugin_common/charset.h src/flac113/plugin_common/defs.h src/flac113/plugin_common/dither.c src/flac113/plugin_common/dither.h src/flac113/plugin_common/locale_hack.h src/flac113/plugin_common/replaygain.c src/flac113/plugin_common/replaygain.h src/flac113/plugin_common/tags.c src/flac113/plugin_common/tags.h src/flac113/replaygain.c src/flac113/replaygain_analysis.c src/flac113/replaygain_analysis.h src/flac113/replaygain_synthesis.c src/flac113/replaygain_synthesis.h src/flac113/tag.c src/flac113/tag.h
diffstat 73 files changed, 6569 insertions(+), 6561 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Oct 23 19:46:25 2006 -0700
+++ b/ChangeLog	Mon Oct 23 19:51:39 2006 -0700
@@ -1,3 +1,11 @@
+2006-10-24 02:46:25 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [204]
+  - revert to r198
+  
+  trunk/src/flac/plugin_common/all.h |    7 -------
+  1 file changed, 7 deletions(-)
+
+
 2006-10-24 02:21:36 +0000  William Pitcock <nenolod@nenolod.net>
   revision [202]
   - plugin now builds on audacious 1.1.2, don't expect it to work
--- a/src/flac/Makefile	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-include ../../mk/rules.mk
-include ../../mk/init.mk
-
-SUBDIRS = plugin_common
-
-noinst_HEADERS = \
-	charset.h \
-	configure.h \
-	http.h \
-	plugin.h \
-	tag.h \
-	fast_float_math_hack.h \
-	replaygain_analysis.h \
-	grabbag.h \
-	replaygain_synthesis.h
-
-OBJECTIVE_LIBS = libflac$(SHARED_SUFFIX)
-
-LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR)
-
-LIBADD = $(LIBFLAC_LIBS)  -L./plugin_common -lplugin_common
-
-SOURCES = \
-	charset.c \
-	configure.c \
-	fileinfo.c \
-	http.c \
-	plugin.c \
-	tag.c \
-	replaygain_synthesis.c \
-	replaygain.c \
-	replaygain_analysis.c \
-	file.c
-
-OBJECTS = ${SOURCES:.c=.o}
-
-CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../.. $(LIBFLAC_CFLAGS)
-
-include ../../mk/objective.mk
--- a/src/flac/charset.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * Almost from charset.c
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <stdlib.h>
-#include <glib.h>
-#include <string.h>
-#include <errno.h>
-
-#include "plugin_common/charset.h"
-#include "plugin_common/locale_hack.h"
-#include "charset.h"
-#include "configure.h"
-
-
-/****************
- * Declarations *
- ****************/
-
-#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) )
-const CharsetInfo charset_trans_array[] = {
-	{N_("Arabic (IBM-864)"),                  "IBM864"        },
-	{N_("Arabic (ISO-8859-6)"),               "ISO-8859-6"    },
-	{N_("Arabic (Windows-1256)"),             "windows-1256"  },
-	{N_("Baltic (ISO-8859-13)"),              "ISO-8859-13"   },
-	{N_("Baltic (ISO-8859-4)"),               "ISO-8859-4"    },
-	{N_("Baltic (Windows-1257)"),             "windows-1257"  },
-	{N_("Celtic (ISO-8859-14)"),              "ISO-8859-14"   },
-	{N_("Central European (IBM-852)"),        "IBM852"        },
-	{N_("Central European (ISO-8859-2)"),     "ISO-8859-2"    },
-	{N_("Central European (Windows-1250)"),   "windows-1250"  },
-	{N_("Chinese Simplified (GB18030)"),      "gb18030"       },
-	{N_("Chinese Simplified (GB2312)"),       "GB2312"        },
-	{N_("Chinese Traditional (Big5)"),        "Big5"          },
-	{N_("Chinese Traditional (Big5-HKSCS)"),  "Big5-HKSCS"    },
-	{N_("Cyrillic (IBM-855)"),                "IBM855"        },
-	{N_("Cyrillic (ISO-8859-5)"),             "ISO-8859-5"    },
-	{N_("Cyrillic (ISO-IR-111)"),             "ISO-IR-111"    },
-	{N_("Cyrillic (KOI8-R)"),                 "KOI8-R"        },
-	{N_("Cyrillic (Windows-1251)"),           "windows-1251"  },
-	{N_("Cyrillic/Russian (CP-866)"),         "IBM866"        },
-	{N_("Cyrillic/Ukrainian (KOI8-U)"),       "KOI8-U"        },
-	{N_("English (US-ASCII)"),                "us-ascii"      },
-	{N_("Greek (ISO-8859-7)"),                "ISO-8859-7"    },
-	{N_("Greek (Windows-1253)"),              "windows-1253"  },
-	{N_("Hebrew (IBM-862)"),                  "IBM862"        },
-	{N_("Hebrew (Windows-1255)"),             "windows-1255"  },
-	{N_("Japanese (EUC-JP)"),                 "EUC-JP"        },
-	{N_("Japanese (ISO-2022-JP)"),            "ISO-2022-JP"   },
-	{N_("Japanese (Shift_JIS)"),              "Shift_JIS"     },
-	{N_("Korean (EUC-KR)"),                   "EUC-KR"        },
-	{N_("Nordic (ISO-8859-10)"),              "ISO-8859-10"   },
-	{N_("South European (ISO-8859-3)"),       "ISO-8859-3"    },
-	{N_("Thai (TIS-620)"),                    "TIS-620"       },
-	{N_("Turkish (IBM-857)"),                 "IBM857"        },
-	{N_("Turkish (ISO-8859-9)"),              "ISO-8859-9"    },
-	{N_("Turkish (Windows-1254)"),            "windows-1254"  },
-	{N_("Unicode (UTF-7)"),                   "UTF-7"         },
-	{N_("Unicode (UTF-8)"),                   "UTF-8"         },
-	{N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
-	{N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
-	{N_("Unicode (UTF-32BE)"),                "UTF-32BE"      },
-	{N_("Unicode (UTF-32LE)"),                "UTF-32LE"      },
-	{N_("Vietnamese (VISCII)"),               "VISCII"        },
-	{N_("Vietnamese (Windows-1258)"),         "windows-1258"  },
-	{N_("Visual Hebrew (ISO-8859-8)"),        "ISO-8859-8"    },
-	{N_("Western (IBM-850)"),                 "IBM850"        },
-	{N_("Western (ISO-8859-1)"),              "ISO-8859-1"    },
-	{N_("Western (ISO-8859-15)"),             "ISO-8859-15"   },
-	{N_("Western (Windows-1252)"),            "windows-1252"  }
-
-	/*
-	 * From this point, character sets aren't supported by iconv
-	 */
-#if 0
-	{N_("Arabic (IBM-864-I)"),                "IBM864i"              },
-	{N_("Arabic (ISO-8859-6-E)"),             "ISO-8859-6-E"         },
-	{N_("Arabic (ISO-8859-6-I)"),             "ISO-8859-6-I"         },
-	{N_("Arabic (MacArabic)"),                "x-mac-arabic"         },
-	{N_("Armenian (ARMSCII-8)"),              "armscii-8"            },
-	{N_("Central European (MacCE)"),          "x-mac-ce"             },
-	{N_("Chinese Simplified (GBK)"),          "x-gbk"                },
-	{N_("Chinese Simplified (HZ)"),           "HZ-GB-2312"           },
-	{N_("Chinese Traditional (EUC-TW)"),      "x-euc-tw"             },
-	{N_("Croatian (MacCroatian)"),            "x-mac-croatian"       },
-	{N_("Cyrillic (MacCyrillic)"),            "x-mac-cyrillic"       },
-	{N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian"      },
-	{N_("Farsi (MacFarsi)"),                  "x-mac-farsi"},
-	{N_("Greek (MacGreek)"),                  "x-mac-greek"          },
-	{N_("Gujarati (MacGujarati)"),            "x-mac-gujarati"       },
-	{N_("Gurmukhi (MacGurmukhi)"),            "x-mac-gurmukhi"       },
-	{N_("Hebrew (ISO-8859-8-E)"),             "ISO-8859-8-E"         },
-	{N_("Hebrew (ISO-8859-8-I)"),             "ISO-8859-8-I"         },
-	{N_("Hebrew (MacHebrew)"),                "x-mac-hebrew"         },
-	{N_("Hindi (MacDevanagari)"),             "x-mac-devanagari"     },
-	{N_("Icelandic (MacIcelandic)"),          "x-mac-icelandic"      },
-	{N_("Korean (JOHAB)"),                    "x-johab"              },
-	{N_("Korean (UHC)"),                      "x-windows-949"        },
-	{N_("Romanian (MacRomanian)"),            "x-mac-romanian"       },
-	{N_("Turkish (MacTurkish)"),              "x-mac-turkish"        },
-	{N_("User Defined"),                      "x-user-defined"       },
-	{N_("Vietnamese (TCVN)"),                 "x-viet-tcvn5712"      },
-	{N_("Vietnamese (VPS)"),                  "x-viet-vps"           },
-	{N_("Western (MacRoman)"),                "x-mac-roman"          },
-	/* charsets whithout posibly translatable names */
-	{"T61.8bit",                              "T61.8bit"             },
-	{"x-imap4-modified-utf7",                 "x-imap4-modified-utf7"},
-	{"x-u-escaped",                           "x-u-escaped"          },
-	{"windows-936",                           "windows-936"          }
-#endif
-};
-
-/*************
- * Functions *
- *************/
-
-/*
- * Commons conversion functions
- */
-char *convert_from_utf8_to_user(const char *string)
-{
-	return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set);
-}
-
-char *convert_from_user_to_utf8(const char *string)
-{
-	return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8");
-}
-
-GList *Charset_Create_List (void)
-{
-	GList *list = NULL;
-	guint i;
-
-	for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
-		list = g_list_append(list,_(charset_trans_array[i].charset_title));
-	return list;
-}
-
-GList *Charset_Create_List_UTF8_Only (void)
-{
-	GList *list = NULL;
-
-	list = g_list_append(list,_(Charset_Get_Title_From_Name("UTF-8")));
-	return list;
-}
-
-
-/*
- * Return charset_name from charset_title
- */
-gchar *Charset_Get_Name_From_Title (const gchar *charset_title)
-{
-	guint i;
-
-	if (charset_title)
-		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
-			if ( strcasecmp(_(charset_title),_(charset_trans_array[i].charset_title)) == 0 )
-				return charset_trans_array[i].charset_name;
-	return "";
-}
-
-
-/*
- * Return charset_title from charset_name
- */
-gchar *Charset_Get_Title_From_Name (const gchar *charset_name)
-{
-	guint i;
-
-	if (charset_name)
-		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
-			if ( strcasecmp(charset_name,charset_trans_array[i].charset_name) == 0 )
-				return _(charset_trans_array[i].charset_title);
-	return "";
-}
--- a/src/flac/charset.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * Almost from charset.h - 2001/12/04
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-
-#ifndef __CHARSET_H__
-#define __CHARSET_H__
-
-
-/***************
- * Declaration *
- ***************/
-
-typedef struct {
-	gchar *charset_title;
-	gchar *charset_name;
-} CharsetInfo;
-
-/* translated charset titles */
-extern const CharsetInfo charset_trans_array[];
-
-/**************
- * Prototypes *
- **************/
-
-/*
- * The returned strings are malloc()ed an must be free()d by the caller
- */
-char *convert_from_utf8_to_user(const char *string);
-char *convert_from_user_to_utf8(const char *string);
-
-GList *Charset_Create_List (void);
-GList *Charset_Create_List_UTF8_Only (void);
-gchar *Charset_Get_Name_From_Title (const gchar *charset_title);
-gchar *Charset_Get_Title_From_Name (const gchar *charset_name);
-
-#endif /* __CHARSET_H__ */
-
--- a/src/flac/configure.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,685 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * Based on mpg123 plugin
- *          and prefs.c - 2000/05/06
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 2000-2002  Jerome Couderc <j.couderc@ifrance.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <math.h>
-
-#include <audacious/configdb.h>
-#include <audacious/dirbrowser.h>
-#include <audacious/titlestring.h>
-#include <audacious/util.h>
-#include <audacious/plugin.h>
-
-#include "plugin_common/locale_hack.h"
-#include "replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */
-#include "charset.h"
-#include "configure.h"
-
-/*
- * Initialize Global Valueable
- */
-flac_config_t flac_cfg = {
-	/* title */
-	{
-		FALSE, /* tag_override */
-		NULL, /* tag_format */
-		FALSE, /* convert_char_set */
-		NULL /* user_char_set */
-	},
-	/* stream */
-	{
-		100 /* KB */, /* http_buffer_size */
-		50, /* http_prebuffer */
-		FALSE, /* use_proxy */
-		"", /* proxy_host */
-		0, /* proxy_port */
-		FALSE, /* proxy_use_auth */
-		"", /* proxy_user */
-		"", /* proxy_pass */
-		FALSE, /* save_http_stream */
-		"", /* save_http_path */
-		FALSE, /* cast_title_streaming */
-		FALSE /* use_udp_channel */
-	},
-	/* output */
-	{
-		/* replaygain */
-		{
-			FALSE, /* enable */
-			TRUE, /* album_mode */
-			0, /* preamp */
-			FALSE /* hard_limit */
-		},
-		/* resolution */
-		{
-			/* normal */
-			{
-				TRUE /* dither_24_to_16 */
-			},
-			/* replaygain */
-			{
-				TRUE, /* dither */
-				NOISE_SHAPING_LOW, /* noise_shaping */
-				16 /* bps_out */
-			}
-		}
-	}
-};
-
-
-static GtkWidget *flac_configurewin = NULL;
-static GtkWidget *vbox, *notebook;
-
-static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc;
-static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry;
-static GtkWidget *replaygain_enable, *replaygain_album_mode;
-static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit;
-static GtkObject *replaygain_preamp;
-static GtkWidget *resolution_normal_dither_24_to_16;
-static GtkWidget *resolution_replaygain_dither;
-static GtkWidget *resolution_replaygain_noise_shaping_frame;
-static GtkWidget *resolution_replaygain_noise_shaping_radio_none;
-static GtkWidget *resolution_replaygain_noise_shaping_radio_low;
-static GtkWidget *resolution_replaygain_noise_shaping_radio_medium;
-static GtkWidget *resolution_replaygain_noise_shaping_radio_high;
-static GtkWidget *resolution_replaygain_bps_out_frame;
-static GtkWidget *resolution_replaygain_bps_out_radio_16bps;
-static GtkWidget *resolution_replaygain_bps_out_radio_24bps;
-
-static GtkObject *streaming_size_adj, *streaming_pre_adj;
-static GtkWidget *streaming_save_use, *streaming_save_entry;
-#ifdef FLAC_ICECAST
-static GtkWidget *streaming_cast_title, *streaming_udp_title;
-#endif
-static GtkWidget *streaming_save_dirbrowser;
-static GtkWidget *streaming_save_hbox;
-
-static const gchar *gtk_entry_get_text_1 (GtkWidget *widget);
-static void flac_configurewin_ok(GtkWidget * widget, gpointer data);
-static void configure_destroy(GtkWidget * w, gpointer data);
-
-static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
-{
-	ConfigDb *db;
-
-	(void)widget, (void)data; /* unused arguments */
-	g_free(flac_cfg.title.tag_format);
-	flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry)));
-	flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry));
-
-	db = bmp_cfg_db_open();
-	/* title */
-	bmp_cfg_db_set_bool(db, "flac", "title.tag_override", flac_cfg.title.tag_override);
-	bmp_cfg_db_set_string(db, "flac", "title.tag_format", flac_cfg.title.tag_format);
-	bmp_cfg_db_set_bool(db, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set);
-	bmp_cfg_db_set_string(db, "flac", "title.user_char_set", flac_cfg.title.user_char_set);
-	/* output */
-	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable);
-	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode);
-	bmp_cfg_db_set_int(db, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp);
-	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit);
-	bmp_cfg_db_set_bool(db, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16);
-	bmp_cfg_db_set_bool(db, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither);
-	bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping);
-	bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out);
-	/* streaming */
-	flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value;
-	flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value;
-
-	flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
-
-	if (flac_cfg.stream.save_http_path != NULL)
-		g_free(flac_cfg.stream.save_http_path);
-
-	flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry)));
-
-#ifdef FLAC_ICECAST
-	flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title));
-	flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title));
-#endif
-
-	bmp_cfg_db_set_int(db, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size);
-	bmp_cfg_db_set_int(db, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer);
-	bmp_cfg_db_set_bool(db, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream);
-	bmp_cfg_db_set_string(db, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path);
-#ifdef FLAC_ICECAST
-	bmp_cfg_db_set_bool(db, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming);
-	bmp_cfg_db_set_bool(db, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel);
-#endif
-
-	bmp_cfg_db_close(db);
-	gtk_widget_destroy(flac_configurewin);
-}
-
-static void configure_destroy(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-}
-
-static void title_tag_override_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override));
-
-	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
-	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
-
-}
-
-static void convert_char_set_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set));
-
-	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
-	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
-}
-
-static void replaygain_enable_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable));
-
-	gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable);
-	gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable);
-	gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable);
-}
-
-static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode));
-}
-
-static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit));
-}
-
-static void replaygain_preamp_cb(GtkWidget *widget, gpointer data)
-{
-	GString *gstring = g_string_new("");
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5);
-
-	g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp);
-	gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str));
-}
-
-static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16));
-}
-
-static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither));
-
-	gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither);
-}
-
-static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.resolution.replaygain.noise_shaping =
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 :
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 :
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 :
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 :
-		0
-	;
-}
-
-static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data)
-{
-	(void)widget, (void)data; /* unused arguments */
-	flac_cfg.output.resolution.replaygain.bps_out =
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 :
-		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 :
-		16
-	;
-}
-
-static void streaming_save_dirbrowser_cb(gchar * dir)
-{
-	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir);
-}
-
-static void streaming_save_browse_cb(GtkWidget * w, gpointer data)
-{
-	(void) w;
-	(void) data;
-	if (!streaming_save_dirbrowser)
-	{
-		streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"),
-								    flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb);
-		gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser);
-		gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin));
-		gtk_widget_show(streaming_save_dirbrowser);
-	}
-}
-
-static void streaming_save_use_cb(GtkWidget * w, gpointer data)
-{
-	gboolean save_stream;
-	(void) w;
-	(void) data;
-
-	save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
-
-	gtk_widget_set_sensitive(streaming_save_hbox, save_stream);
-}
-
-
-void FLAC_XMMS__configure(void)
-{
-	GtkWidget *title_frame, *title_tag_vbox, *title_tag_label;
-	GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame;
-	GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox;
-	GtkWidget *resolution_replaygain_noise_shaping_vbox;
-	GtkWidget *resolution_replaygain_bps_out_vbox;
-	GtkWidget *label, *hbox;
-	GtkWidget *bbox, *ok, *cancel;
-	GList *list;
-
-	GtkWidget *streaming_vbox;
-	GtkWidget *streaming_buf_frame, *streaming_buf_hbox;
-	GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin;
-	GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin;
-	GtkWidget *streaming_save_frame, *streaming_save_vbox;
-	GtkWidget *streaming_save_label, *streaming_save_browse;
-#ifdef FLAC_ICECAST
-	GtkWidget *streaming_cast_frame, *streaming_cast_vbox;
-#endif
-
-	if (flac_configurewin != NULL) {
-		gdk_window_raise(flac_configurewin->window);
-		return;
-	}
-	flac_configurewin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin);
-	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin);
-	gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration"));
-	gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE);
-	gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10);
-
-	vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox);
-
-	notebook = gtk_notebook_new();
-	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-	/* Title config.. */
-
-	title_frame = gtk_frame_new(_("Tag Handling"));
-	gtk_container_border_width(GTK_CONTAINER(title_frame), 5);
-
-	title_tag_vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox);
-
-	/* Convert Char Set */
-
-	convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set);
-	gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", (GCallback)convert_char_set_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0);
-	/*  Combo boxes... */
-	hbox = gtk_hbox_new(FALSE,4);
-	gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox);
-	label = gtk_label_new(_("Convert character set from :"));
-	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
-	fileCharacterSetEntry = gtk_combo_new();
-	gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0);
-
-	label = gtk_label_new (_("to :"));
-	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
-	userCharacterSetEntry = gtk_combo_new();
-	gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0);
-
-	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE);
-	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE);
-	gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE);
-	gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE);
-
-	list = Charset_Create_List();
-	gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only());
-	gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list);
-	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set));
-	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
-	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
-
-	/* Override Tagging Format */
-
-	title_tag_override = gtk_check_button_new_with_label(_("Override generic titles"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override);
-	gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", (GCallback)title_tag_override_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0);
-
-	title_tag_box = gtk_hbox_new(FALSE, 5);
-	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
-	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0);
-
-	title_tag_label = gtk_label_new(_("Title format:"));
-	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0);
-
-	title_tag_entry = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format);
-	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0);
-
-	title_desc = xmms_titlestring_descriptions("pafFetnygc", 2);
-	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
-	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0);
-
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title")));
-
-	/* Output config.. */
-
-	output_vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(output_vbox), 5);
-
-	/* replaygain */
-
-	replaygain_frame = gtk_frame_new(_("ReplayGain"));
-	gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5);
-	gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0);
-
-	replaygain_vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox);
-
-	replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable);
-	gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", (GCallback)replaygain_enable_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0);
-
-	replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode);
-	gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", (GCallback)replaygain_album_mode_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0);
-
-	hbox = gtk_hbox_new(FALSE,3);
-	gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox);
-	label = gtk_label_new(_("Preamp:"));
-	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
-	replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0);
-	gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", (GCallback)replaygain_preamp_cb, NULL);
-	replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp));
-	gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE);
-	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0);
-	replaygain_preamp_label = gtk_label_new(_("0 dB"));
-	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0);
-	gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp));
-
-	replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit);
-	gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", (GCallback)replaygain_hard_limit_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0);
-
-	replaygain_enable_cb(replaygain_enable, NULL);
-
-	/* resolution */
-
-	resolution_frame = gtk_frame_new(_("Resolution"));
-	gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5);
-	gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0);
-
-	resolution_hbox = gtk_hbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5);
-	gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox);
-
-	resolution_normal_frame = gtk_frame_new(_("Without ReplayGain"));
-	gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5);
-	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0);
-
-	resolution_normal_vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox);
-
-	resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16);
-	gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", (GCallback)resolution_normal_dither_24_to_16_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0);
-
-	resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain"));
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5);
-	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0);
-
-	resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox);
-
-	resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", (GCallback)resolution_replaygain_dither_cb, NULL);
-	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0);
-
-	hbox = gtk_hbox_new(FALSE, 10);
-	gtk_container_border_width(GTK_CONTAINER(hbox), 5);
-	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0);
-
-	resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping"));
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5);
-	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0);
-
-	resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new();
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox);
-
-	resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none"));
-	if(flac_cfg.output.resolution.replaygain.noise_shaping == 0)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none);
-
-	resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low"));
-	if(flac_cfg.output.resolution.replaygain.noise_shaping == 1)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low);
-
-	resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium"));
-	if(flac_cfg.output.resolution.replaygain.noise_shaping == 2)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium);
-
-	resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high"));
-	if(flac_cfg.output.resolution.replaygain.noise_shaping == 3)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high);
-
-	resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to"));
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5);
-	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0);
-
-	resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new();
-	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox);
-
-	resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps"));
-	if(flac_cfg.output.resolution.replaygain.bps_out == 16)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps);
-
-	resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps"));
-	if(flac_cfg.output.resolution.replaygain.bps_out == 24)
-		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE);
-	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL);
-	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps);
-
-	resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL);
-
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output")));
-
-	/* Streaming */
-
-	streaming_vbox = gtk_vbox_new(FALSE, 0);
-
-	streaming_buf_frame = gtk_frame_new(_("Buffering:"));
-	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5);
-	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0);
-
-	streaming_buf_hbox = gtk_hbox_new(TRUE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5);
-	gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox);
-
-	streaming_size_box = gtk_hbox_new(FALSE, 5);
-	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */
-	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0);
-	streaming_size_label = gtk_label_new(_("Buffer size (kb):"));
-	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0);
-	streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4);
-	streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0);
-	gtk_widget_set_usize(streaming_size_spin, 60, -1);
-	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0);
-
-	streaming_pre_box = gtk_hbox_new(FALSE, 5);
-	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */
-	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0);
-	streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):"));
-	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0);
-	streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1);
-	streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0);
-	gtk_widget_set_usize(streaming_pre_spin, 60, -1);
-	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0);
-
-	/*
-	 * Save to disk config.
-	 */
-	streaming_save_frame = gtk_frame_new(_("Save stream to disk:"));
-	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5);
-	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0);
-
-	streaming_save_vbox = gtk_vbox_new(FALSE, 5);
-	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5);
-	gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox);
-
-	streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream);
-	gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL);
-	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0);
-
-	streaming_save_hbox = gtk_hbox_new(FALSE, 5);
-	gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream);
-	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0);
-
-	streaming_save_label = gtk_label_new(_("Path:"));
-	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0);
-
-	streaming_save_entry = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path);
-	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0);
-
-	streaming_save_browse = gtk_button_new_with_label(_("Browse"));
-	gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL);
-	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0);
-
-#ifdef FLAC_ICECAST
-	streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:"));
-	gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5);
-	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0);
-
-	streaming_cast_vbox = gtk_vbox_new(5, FALSE);
-	gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox);
-
-	streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming);
-	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0);
-
-	streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel"));
-	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel);
-	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0);
-#endif
-
-	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming")));
-
-	/* Buttons */
-
-	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(flac_configurewin_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(flac_configurewin));
-	GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
-	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
-
-	gtk_widget_show_all(flac_configurewin);
-}
-
-void FLAC_XMMS__aboutbox()
-{
-	static GtkWidget *about_window;
-
-	if (about_window)
-		gdk_window_raise(about_window->window);
-	else
-	{
-		about_window = xmms_show_message(
-			_("About Flac Plugin"),
-			_("Flac Plugin by Josh Coalson\n"
-			  "contributions by\n"
-			  "......\n"
-			  "......\n"
-			  "and\n"
-			  "Daisuke Shimamura\n"
-			  "Visit http://flac.sourceforge.net/"),
-			_("Ok"), FALSE, NULL, NULL);
-		gtk_signal_connect(GTK_OBJECT(about_window), "destroy",
-				   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
-				   &about_window);
-	}
-}
-
-/*
- * Get text of an Entry or a ComboBox
- */
-static const gchar *gtk_entry_get_text_1 (GtkWidget *widget)
-{
-	if (GTK_IS_COMBO(widget))
-	{
-		return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry));
-	}else if (GTK_IS_ENTRY(widget))
-	{
-		return gtk_entry_get_text(GTK_ENTRY(widget));
-	}else
-	{
-		return NULL;
-	}
-}
--- a/src/flac/configure.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * Based on mpg123 plugin
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef __CONFIGURE_H__
-#define __CONFIGURE_H__
-
-#include <glib.h>
-
-typedef struct {
-	struct {
-		gboolean tag_override;
-		gchar *tag_format;
-		gboolean convert_char_set;
-		gchar *user_char_set;
-	} title;
-
-	struct {
-		gint http_buffer_size;
-		gint http_prebuffer;
-		gboolean use_proxy; 
-		gchar *proxy_host;
-		gint proxy_port;
-		gboolean proxy_use_auth;
-		gchar *proxy_user;
-		gchar	*proxy_pass;
-		gboolean save_http_stream;
-		gchar *save_http_path;
-		gboolean cast_title_streaming;
-		gboolean use_udp_channel;
-	} stream;
-
-	struct {
-		struct {
-			gboolean enable;
-			gboolean album_mode;
-			gint preamp;
-			gboolean hard_limit;
-		} replaygain;
-		struct {
-			struct {
-				gboolean dither_24_to_16;
-			} normal;
-			struct {
-				gboolean dither;
-				gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
-				gint bps_out;
-			} replaygain;
-		} resolution;
-	} output;
-} flac_config_t;
-
-extern flac_config_t flac_cfg;
-
-extern void FLAC_XMMS__configure(void);
-extern void FLAC_XMMS__aboutbox();
-
-#endif
-
-
-
--- a/src/flac/fast_float_math_hack.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#   ifdef __ICL /* only Intel C compiler has fmath ??? */
-
-    #include <mathf.h>
-
-/* Nearest integer, absolute value, etc. */
-
-    #define ceil ceilf
-    #define fabs fabsf
-    #define floor floorf
-    #define fmod fmodf
-    #define rint rintf
-    #define hypot hypotf
-
-/* Power functions */
-
-    #define pow powf
-    #define sqrt sqrtf
-
-/* Exponential and logarithmic functions */
-
-    #define exp expf
-    #define log logf
-    #define log10 log10f
-
-/* Trigonometric functions */
-
-    #define acos acosf
-    #define asin asinf
-    #define atan atanf
-    #define cos cosf
-    #define sin sinf
-    #define tan tanf
-
-/* Hyperbolic functions */
-    #define cosh coshf
-    #define sinh sinhf
-    #define tanh tanhf
-
-#   endif
--- a/src/flac/file.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#if defined _MSC_VER || defined __MINGW32__
-#include <sys/utime.h> /* for utime() */
-#include <io.h> /* for chmod(), _setmode(), unlink() */
-#include <fcntl.h> /* for _O_BINARY */
-#else
-#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
-#include <utime.h> /* for utime() */
-#endif
-#ifdef __CYGWIN__
-#include <io.h> /* for setmode(), O_BINARY */
-#include <fcntl.h> /* for _O_BINARY */
-#endif
-#include <sys/stat.h> /* for stat(), maybe chmod() */
-#if defined _WIN32 && !defined __CYGWIN__
-#else
-#include <unistd.h> /* for unlink() */
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> /* for strrchr() */
-#include "grabbag.h"
-
-
-void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
-{
-	struct stat srcstat;
-	struct utimbuf srctime;
-
-	if(0 == stat(srcpath, &srcstat)) {
-		srctime.actime = srcstat.st_atime;
-		srctime.modtime = srcstat.st_mtime;
-		(void)chmod(destpath, srcstat.st_mode);
-		(void)utime(destpath, &srctime);
-	}
-}
-
-off_t grabbag__file_get_filesize(const char *srcpath)
-{
-	struct stat srcstat;
-
-	if(0 == stat(srcpath, &srcstat))
-		return srcstat.st_size;
-	else
-		return -1;
-}
-
-const char *grabbag__file_get_basename(const char *srcpath)
-{
-	const char *p;
-
-	p = strrchr(srcpath, '/');
-	if(0 == p) {
-		p = strrchr(srcpath, '\\');
-		if(0 == p)
-			return srcpath;
-	}
-	return ++p;
-}
-
-FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
-{
-	struct stat stats;
-
-	if(0 == stat(filename, &stats)) {
-#if !defined _MSC_VER && !defined __MINGW32__
-		if(read_only) {
-			stats.st_mode &= ~S_IWUSR;
-			stats.st_mode &= ~S_IWGRP;
-			stats.st_mode &= ~S_IWOTH;
-		}
-		else {
-			stats.st_mode |= S_IWUSR;
-		}
-#else
-		if(read_only)
-			stats.st_mode &= ~S_IWRITE;
-		else
-			stats.st_mode |= S_IWRITE;
-#endif
-		if(0 != chmod(filename, stats.st_mode))
-			return false;
-	}
-	else
-		return false;
-
-	return true;
-}
-
-FLAC__bool grabbag__file_remove_file(const char *filename)
-{
-	return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename);
-}
-
-FILE *grabbag__file_get_binary_stdin()
-{
-	/* if something breaks here it is probably due to the presence or
-	 * absence of an underscore before the identifiers 'setmode',
-	 * 'fileno', and/or 'O_BINARY'; check your system header files.
-	 */
-#if defined _MSC_VER || defined __MINGW32__
-	_setmode(_fileno(stdin), _O_BINARY);
-#elif defined __CYGWIN__
-	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
-	setmode(_fileno(stdin), _O_BINARY);
-#endif
-
-	return stdin;
-}
-
-FILE *grabbag__file_get_binary_stdout()
-{
-	/* if something breaks here it is probably due to the presence or
-	 * absence of an underscore before the identifiers 'setmode',
-	 * 'fileno', and/or 'O_BINARY'; check your system header files.
-	 */
-#if defined _MSC_VER || defined __MINGW32__
-	_setmode(_fileno(stdout), _O_BINARY);
-#elif defined __CYGWIN__
-	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
-	setmode(_fileno(stdout), _O_BINARY);
-#endif
-
-	return stdout;
-}
--- a/src/flac/fileinfo.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,500 +0,0 @@
-/*  XMMS - Cross-platform multimedia player
- *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
- *  Copyright (C) 1999,2000  Håvard Kvålen
- *  Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <stdlib.h>
-#include <string.h> /* for strlen() */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <gtk/gtk.h>
-
-#include "audacious/util.h"
-#include "FLAC/metadata.h"
-#include "charset.h"
-#include "configure.h"
-#include "plugin_common/locale_hack.h"
-#include "plugin_common/replaygain.h"
-#include "plugin_common/tags.h"
-
-static GtkWidget *window = NULL;
-static GList *genre_list = NULL;
-static GtkWidget *filename_entry, *tag_frame;
-static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry;
-static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak;
-static GtkWidget *genre_combo;
-static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate;
-
-static gchar *current_filename = NULL;
-static FLAC__StreamMetadata *tags_ = NULL;
-
-static const gchar *vorbis_genres[] =
-{
-	N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
-	N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
-	N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
-	N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
-	N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
-	N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
-	N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
-	N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
-	N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
-	N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"),
-	N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
-	N_("Meditative"), N_("Instrumental Pop"),
-	N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
-	N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
-	N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
-	N_("Southern Rock"), N_("Comedy"), N_("Cult"),
-	N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
-	N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
-	N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
-	N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
-	N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
-	N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
-	N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
-	N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
-	N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
-	N_("Gothic Rock"), N_("Progressive Rock"),
-	N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
-	N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
-	N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
-	N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
-	N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
-	N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
-	N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
-	N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
-	N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
-	N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
-	N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
-	N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
-	N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
-	N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
-	N_("Contemporary Christian"), N_("Christian Rock"),
-	N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
-	N_("Anime"), N_("JPop"), N_("Synthpop")
-};
-
-static void label_set_text(GtkWidget * label, char *str, ...)
-{
-	va_list args;
-	gchar *tempstr;
-
-	va_start(args, str);
-	tempstr = g_strdup_vprintf(str, args);
-	va_end(args);
-
-	gtk_label_set_text(GTK_LABEL(label), tempstr);
-	g_free(tempstr);
-}
-
-static void set_entry_tag(GtkEntry * entry, const char * utf8)
-{
-	if(utf8) {
-		if(flac_cfg.title.convert_char_set) {
-			char *text = convert_from_utf8_to_user(utf8);
-			gtk_entry_set_text(entry, text);
-			free(text);
-		}
-		else
-			gtk_entry_set_text(entry, utf8);
-	}
-	else
-		gtk_entry_set_text(entry, "");
-}
-
-static void get_entry_tag(GtkEntry * entry, const char *name)
-{
-	gchar *text;
-	char *utf8;
-
-	text = g_strdup(gtk_entry_get_text(entry));
-	if (!text || strlen(text) == 0) 
-	{
-		g_free(text);
-		return;
-	}
-	if(flac_cfg.title.convert_char_set)
-		utf8 = convert_from_user_to_utf8(text);
-	else
-		utf8 = text;
-
-	FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0);
-
-	if(flac_cfg.title.convert_char_set)
-		free(utf8);
-	g_free(text);
-}
-
-static void show_tag()
-{
-	set_entry_tag(GTK_ENTRY(title_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE"));
-	set_entry_tag(GTK_ENTRY(artist_entry)                 , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST"));
-	set_entry_tag(GTK_ENTRY(album_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM"));
-	set_entry_tag(GTK_ENTRY(date_entry)                   , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE"));
-	set_entry_tag(GTK_ENTRY(tracknum_entry)               , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER"));
-	set_entry_tag(GTK_ENTRY(comment_entry)                , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION"));
-	set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE"));
-}
-
-static void save_tag(GtkWidget * w, gpointer data)
-{
-	(void)w;
-	(void)data;
-
-	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
-	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
-	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
-	FLAC_plugin__tags_delete_tag(tags_, "DATE");
-	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
-	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
-	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
-
-	get_entry_tag(GTK_ENTRY(title_entry)                  , "TITLE");
-	get_entry_tag(GTK_ENTRY(artist_entry)                 , "ARTIST");
-	get_entry_tag(GTK_ENTRY(album_entry)                  , "ALBUM");
-	get_entry_tag(GTK_ENTRY(date_entry)                   , "DATE");
-	get_entry_tag(GTK_ENTRY(tracknum_entry)               , "TRACKNUMBER");
-	get_entry_tag(GTK_ENTRY(comment_entry)                , "DESCRIPTION");
-	get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE");
-
-	FLAC_plugin__tags_set(current_filename, tags_);
-	gtk_widget_destroy(window);
-}
-
-static void remove_tag(GtkWidget * w, gpointer data)
-{
-	(void)w;
-	(void)data;
-	
-	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
-	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
-	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
-	FLAC_plugin__tags_delete_tag(tags_, "DATE");
-	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
-	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
-	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
-
-	FLAC_plugin__tags_set(current_filename, tags_);
-	gtk_widget_destroy(window);
-}
-
-static void show_file_info()
-{
-	FLAC__StreamMetadata streaminfo;
-	struct stat _stat;
-
-	gtk_label_set_text(GTK_LABEL(flac_samplerate), "");
-	gtk_label_set_text(GTK_LABEL(flac_channels), "");
-	gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), "");
-	gtk_label_set_text(GTK_LABEL(flac_blocksize), "");
-	gtk_label_set_text(GTK_LABEL(flac_filesize), "");
-	gtk_label_set_text(GTK_LABEL(flac_samples), "");
-	gtk_label_set_text(GTK_LABEL(flac_bitrate), "");
-
-	if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) {
-		return;
-	}
-
-	label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate);
-	label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels);
-	label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample);
-	if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize)
-		label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize);
-	else
-		label_set_text(flac_blocksize, _("Blocksize: variable\n  min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize);
-
-	if (streaminfo.data.stream_info.total_samples)
-		label_set_text(flac_samples, _("Samples: %llu\nLength: %d:%.2d"),
-				streaminfo.data.stream_info.total_samples,
-				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60),
-				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60));
-
-	if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) {
-#if _FILE_OFFSET_BITS == 64
-		label_set_text(flac_filesize, _("Filesize: %lld B"), _stat.st_size);
-#else
-		label_set_text(flac_filesize, _("Filesize: %ld B"), _stat.st_size);
-#endif
-		if (streaminfo.data.stream_info.total_samples)
-			label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"),
-					8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate),
-					100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples));
-	}
-}
-
-static void show_replaygain()
-{
-	/* known limitation: If only one of gain and peak is set, neither will be shown. This is true for
-	 * both track and album replaygain tags. Written so it will be easy to fix, with some trouble.  */
-
-	gtk_label_set_text(GTK_LABEL(replaygain_reference), "");
-	gtk_label_set_text(GTK_LABEL(replaygain_track_gain), "");
-	gtk_label_set_text(GTK_LABEL(replaygain_album_gain), "");
-	gtk_label_set_text(GTK_LABEL(replaygain_track_peak), "");
-	gtk_label_set_text(GTK_LABEL(replaygain_album_peak), "");
-
-	double reference, track_gain, track_peak, album_gain, album_peak;
-	FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set;
-
-	FLAC_plugin__replaygain_get_from_file(
-		current_filename,
-		&reference, &reference_set,
-		&track_gain, &track_gain_set,
-		&album_gain, &album_gain_set,
-		&track_peak, &track_peak_set,
-		&album_peak, &album_peak_set
-	);
-
-	if(reference_set)
-		label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference);
-	if(track_gain_set)
-		label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain);
-	if(album_gain_set)
-		label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain);
-	if(track_peak_set)
-		label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak);
-	if(album_peak_set)
-		label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak);
-}
-
-void FLAC_XMMS__file_info_box(char *filename)
-{
-	unsigned i;
-	gchar *title;
-	gchar *filename_utf8;
-
-	if (!window)
-	{
-		GtkWidget *vbox, *hbox, *left_vbox, *table;
-		GtkWidget *flac_frame, *flac_box;
-		GtkWidget *label, *filename_hbox;
-		GtkWidget *bbox, *save, *remove, *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(gtk_widget_destroyed), &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);
-
-		tag_frame = gtk_frame_new(_("Tag:"));
-		gtk_box_pack_start(GTK_BOX(left_vbox), tag_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(tag_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(_("Date:"));
-		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);
-
-		date_entry = gtk_entry_new();
-		gtk_widget_set_usize(date_entry, 40, -1);
-		gtk_table_attach(GTK_TABLE(table), date_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), TRUE);
-
-		if (!genre_list)
-		{
-			for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++)
-				genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]);
-			genre_list = g_list_prepend(genre_list, "");
-			genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp);
-		}
-		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_tag), 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= gtk_button_new_with_label(_("Remove Tag"));
-		gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL);
-		GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT);
-		gtk_box_pack_start(GTK_BOX(bbox), remove, 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);
-
-		flac_frame = gtk_frame_new(_("FLAC Info:"));
-		gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0);
-
-		flac_box = gtk_vbox_new(FALSE, 5);
-		gtk_container_add(GTK_CONTAINER(flac_frame), flac_box);
-		gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10);
-		gtk_box_set_spacing(GTK_BOX(flac_box), 0);
-
-		flac_samplerate = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0);
-
-		flac_channels = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0);
-
-		flac_bits_per_sample = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0);
-
-		flac_blocksize = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0);
-
-		flac_filesize = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0);
-
-		flac_samples = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0);
-
-		flac_bitrate = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0);
-
-		replaygain_reference = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0);
-
-		replaygain_track_gain = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0);
-
-		replaygain_album_gain = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0);
-
-		replaygain_track_peak = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0);
-
-		replaygain_album_peak = gtk_label_new("");
-		gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0);
-		gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT);
-		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0);
-
-		gtk_widget_show_all(window);
-	}
-
-	if(current_filename)
-		g_free(current_filename);
-	if(!(current_filename = g_strdup(filename)))
-		return;
-
-	filename_utf8 = filename_to_utf8(current_filename);
-	title = g_strdup_printf(_("File Info - %s"), g_basename(filename_utf8));
-	gtk_window_set_title(GTK_WINDOW(window), title);
-	g_free(title);
-
-	gtk_entry_set_text(GTK_ENTRY(filename_entry), filename_utf8);
-	gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1);
-
-	g_free(filename_utf8);
-
-	if(tags_)
-		FLAC_plugin__tags_destroy(&tags_);
-
-	FLAC_plugin__tags_get(current_filename, &tags_);
-
-	show_tag();
-	show_file_info();
-	show_replaygain();
-
-	gtk_widget_set_sensitive(tag_frame, TRUE);
-}
--- a/src/flac/grabbag.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef SHARE__GRABBAG_H
-#define SHARE__GRABBAG_H
-
-#include <FLAC/all.h>
-#include "plugin_common/all.h"
-
-
-/* These can't be included by themselves, only from within grabbag.h */
-#include "grabbag/cuesheet.h"
-#include "grabbag/file.h"
-#include "grabbag/replaygain.h"
-#include "grabbag/seektable.h"
-
-
-#endif
--- a/src/flac/grabbag/cuesheet.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
-
-#ifndef GRABBAG__CUESHEET_H
-#define GRABBAG__CUESHEET_H
-
-#include <stdio.h>
-#include "FLAC/metadata.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames);
-void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames);
-
-FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
-
-void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
--- a/src/flac/grabbag/file.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-/* Convenience routines for manipulating files */
-
-/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
-
-#ifndef GRABAG__FILE_H
-#define GRABAG__FILE_H
-
-#include <sys/types.h> /* for off_t */
-#include <stdio.h> /* for FILE */
-#include "FLAC/ordinals.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void grabbag__file_copy_metadata(const char *srcpath, const char *destpath);
-off_t grabbag__file_get_filesize(const char *srcpath);
-const char *grabbag__file_get_basename(const char *srcpath);
-
-/* read_only == false means "make file writable by user"
- * read_only == true means "make file read-only for everyone"
- */
-FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only);
-
-/* attempts to make writable before unlinking */
-FLAC__bool grabbag__file_remove_file(const char *filename);
-
-/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */
-FILE *grabbag__file_get_binary_stdin();
-FILE *grabbag__file_get_binary_stdout();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
--- a/src/flac/grabbag/replaygain.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005,2006 Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-/*
- * This wraps the replaygain_analysis lib, which is LGPL.  This wrapper
- * allows analysis of different input resolutions by automatically
- * scaling the input signal
- */
-
-/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
-
-#ifndef GRABBAG__REPLAYGAIN_H
-#define GRABBAG__REPLAYGAIN_H
-
-#include "FLAC/metadata.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
-
-extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
-extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
-extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */
-extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
-extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
-
-FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
-
-FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
-
-/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */
-FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples);
-
-void grabbag__replaygain_get_album(float *gain, float *peak);
-void grabbag__replaygain_get_title(float *gain, float *peak);
-
-/* These three functions return an error string on error, or NULL if successful */
-const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak);
-const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak);
-const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block);
-const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak);
-const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak);
-const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime);
-const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime);
-const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime);
-const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime);
-
-FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak);
-double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
--- a/src/flac/grabbag/seektable.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-/* Convenience routines for working with seek tables */
-
-/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
-
-#ifndef GRABAG__SEEKTABLE_H
-#define GRABAG__SEEKTABLE_H
-
-#include "FLAC/format.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
--- a/src/flac/http.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,897 +0,0 @@
-/*  XMMS - Cross-platform multimedia player
- *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* modified for FLAC support by Steven Richman (2003) */
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <glib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <audacious/plugin.h>
-#include <audacious/util.h>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "configure.h"
-#include "plugin_common/locale_hack.h"
-#include "FLAC/format.h"
-#include "plugin.h"
-
-#define min(x,y) ((x)<(y)?(x):(y))
-#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
-#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
-
-static gchar *icy_name = NULL;
-static gint icy_metaint = 0;
-
-extern InputPlugin flac_ip;
-
-#undef DEBUG_UDP
-
-/* Static udp channel functions */
-static int udp_establish_listener (gint *sock);
-static int udp_check_for_data(gint sock);
-
-static char *flac_http_get_title(char *url);
-
-static gboolean prebuffering, going, eof = FALSE;
-static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
-static guint64 buffer_read = 0;
-static gchar *buffer;
-static guint64 offset;
-static GThread *thread;
-static GtkWidget *error_dialog = NULL;
-
-static FILE *output_file = NULL;
-
-#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
-
-/* Encode the string S of length LENGTH to base64 format and place it
-   to STORE.  STORE will be 0-terminated, and must point to a writable
-   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
-static void base64_encode (const gchar *s, gchar *store, gint length)
-{
-	/* Conversion table.  */
-	static gchar tbl[64] = {
-		'A','B','C','D','E','F','G','H',
-		'I','J','K','L','M','N','O','P',
-		'Q','R','S','T','U','V','W','X',
-		'Y','Z','a','b','c','d','e','f',
-		'g','h','i','j','k','l','m','n',
-		'o','p','q','r','s','t','u','v',
-		'w','x','y','z','0','1','2','3',
-		'4','5','6','7','8','9','+','/'
-	};
-	gint i;
-	guchar *p = (guchar *)store;
-
-	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
-	for (i = 0; i < length; i += 3)
-	{
-		*p++ = tbl[s[0] >> 2];
-		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
-		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
-		*p++ = tbl[s[2] & 0x3f];
-		s += 3;
-	}
-	/* Pad the result if necessary...  */
-	if (i == length + 1)
-		*(p - 1) = '=';
-	else if (i == length + 2)
-		*(p - 1) = *(p - 2) = '=';
-	/* ...and zero-terminate it.  */
-	*p = '\0';
-}
-
-/* Create the authentication header contents for the `Basic' scheme.
-   This is done by encoding the string `USER:PASS' in base64 and
-   prepending `HEADER: Basic ' to it.  */
-static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
-{
-	gchar *t1, *t2, *res;
-	gint len1 = strlen (user) + 1 + strlen (passwd);
-	gint len2 = BASE64_LENGTH (len1);
-
-	t1 = g_strdup_printf("%s:%s", user, passwd);
-	t2 = g_malloc0(len2 + 1);
-	base64_encode (t1, t2, len1);
-	res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
-	g_free(t2);
-	g_free(t1);
-	
-	return res;
-}
-
-static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
-{
-	gchar *h, *p, *pt, *f, *temp, *ptr;
-
-	temp = g_strdup(url);
-	ptr = temp;
-
-	if (!strncasecmp("http://", ptr, 7))
-		ptr += 7;
-	h = strchr(ptr, '@');
-	f = strchr(ptr, '/');
-	if (h != NULL && (!f || h < f))
-	{
-		*h = '\0';
-		p = strchr(ptr, ':');
-		if (p != NULL && p < h)
-		{
-			*p = '\0';
-			p++;
-			*pass = g_strdup(p);
-		}
-		else
-			*pass = NULL;
-		*user = g_strdup(ptr);
-		h++;
-		ptr = h;
-	}
-	else
-	{
-		*user = NULL;
-		*pass = NULL;
-		h = ptr;
-	}
-	pt = strchr(ptr, ':');
-	if (pt != NULL && (f == NULL || pt < f))
-	{
-		*pt = '\0';
-		*port = atoi(pt + 1);
-	}
-	else
-	{
-		if (f)
-			*f = '\0';
-		*port = 80;
-	}
-	*host = g_strdup(h);
-	
-	if (f)
-		*filename = g_strdup(f + 1);
-	else
-		*filename = NULL;
-	g_free(temp);
-}
-
-void flac_http_close(void)
-{
-	going = FALSE;
-
-	g_thread_join(thread);
-	g_free(icy_name);
-	icy_name = NULL;
-}
-
-
-static gint http_used(void)
-{
-	if (wr_index >= rd_index)
-		return wr_index - rd_index;
-	return buffer_length - (rd_index - wr_index);
-}
-
-static gint http_free(void)
-{
-	if (rd_index > wr_index)
-		return (rd_index - wr_index) - 1;
-	return (buffer_length - (wr_index - rd_index)) - 1;
-}
-
-static void http_wait_for_data(gint bytes)
-{
-	while ((prebuffering || http_used() < bytes) && !eof && going)
-		xmms_usleep(10000);
-}
-
-static void show_error_message(gchar *error)
-{
-	if(!error_dialog)
-	{
-		GDK_THREADS_ENTER();
-		error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
-						 NULL, NULL);
-		g_signal_connect(G_OBJECT(error_dialog),
-				   "destroy",
-				   G_CALLBACK(gtk_widget_destroyed),
-				   &error_dialog);
-		GDK_THREADS_LEAVE();
-	}
-}
-
-int flac_http_read(gpointer data, gint length)
-{
-	gint len, cnt, off = 0, meta_len, meta_off = 0, i;
-	gchar *meta_data, **tags, *temp, *title;
-	if (length > buffer_length) {
-		length = buffer_length;
-	}
-
-	http_wait_for_data(length);
-
-	if (!going)
-		return 0;
-	len = min(http_used(), length);
-
-	while (len && http_used())
-	{
-		if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
-		{
-			meta_len = *((guchar *) buffer + rd_index) * 16;
-			rd_index = (rd_index + 1) % buffer_length;
-			if (meta_len > 0)
-			{
-				http_wait_for_data(meta_len);
-				meta_data = g_malloc0(meta_len);
-				if (http_used() >= meta_len)
-				{
-					while (meta_len)
-					{
-						cnt = min(meta_len, buffer_length - rd_index);
-						memcpy(meta_data + meta_off, buffer + rd_index, cnt);
-						rd_index = (rd_index + cnt) % buffer_length;
-						meta_len -= cnt;
-						meta_off += cnt;
-					}
-					tags = g_strsplit(meta_data, "';", 0);
-
-					for (i = 0; tags[i]; i++)
-					{
-						if (!strncasecmp(tags[i], "StreamTitle=", 12))
-						{
-							temp = g_strdup(tags[i] + 13);
-							title = g_strdup_printf("%s (%s)", temp, icy_name);
-							set_track_info(title, -1);
-							g_free(title);
-							g_free(temp);
-						}
-
-					}
-					g_strfreev(tags);
-
-				}
-				g_free(meta_data);
-			}
-			if (!http_used())
-				http_wait_for_data(length - off);
-			cnt = min3(len, buffer_length - rd_index, http_used());
-		}
-		else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
-			cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
-		else
-			cnt = min3(len, buffer_length - rd_index, http_used());
-		if (output_file)
-			fwrite(buffer + rd_index, 1, cnt, output_file);
-
-		memcpy((gchar *)data + off, buffer + rd_index, cnt);
-		rd_index = (rd_index + cnt) % buffer_length;
-		buffer_read += cnt;
-		len -= cnt;
-		off += cnt;
-	}
-	if (!off) {
-		fprintf(stderr, "returning zero\n");
-	}
-	return off;
-}
-
-static gboolean http_check_for_data(void)
-{
-
-	fd_set set;
-	struct timeval tv;
-	gint ret;
-
-	tv.tv_sec = 0;
-	tv.tv_usec = 20000;
-	FD_ZERO(&set);
-	FD_SET(sock, &set);
-	ret = select(sock + 1, &set, NULL, NULL, &tv);
-	if (ret > 0)
-		return TRUE;
-	return FALSE;
-}
-
-gint flac_http_read_line(gchar * buf, gint size)
-{
-	gint i = 0;
-
-	while (going && i < size - 1)
-	{
-		if (http_check_for_data())
-		{
-			if (read(sock, buf + i, 1) <= 0)
-				return -1;
-			if (buf[i] == '\n')
-				break;
-			if (buf[i] != '\r')
-				i++;
-		}
-	}
-	if (!going)
-		return -1;
-	buf[i] = '\0';
-	return i;
-}
-
-/* returns the file descriptor of the socket, or -1 on error */
-static int http_connect (gchar *url_, gboolean head, guint64 offset)
-{
-	gchar line[1024], *user, *pass, *host, *filename,
-	     *status, *url, *temp, *file;
-	gchar *chost;
-	gint cnt, error, port, cport;
-	guint err_len;
-	gboolean redirect;
-	int udp_sock = 0;
-	fd_set set;
-	struct hostent *hp;
-	struct sockaddr_in address;
-	struct timeval tv;
-
-	url = g_strdup (url_);
-
-	do
-	{
-		redirect=FALSE;
-	
-		g_strstrip(url);
-
-		parse_url(url, &user, &pass, &host, &port, &filename);
-
-		if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
-			temp = g_strconcat(url, "/", NULL);
-		else
-			temp = g_strdup(url);
-		g_free(url);
-		url = temp;
-
-		chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
-		cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
-
-		sock = socket(AF_INET, SOCK_STREAM, 0);
-		fcntl(sock, F_SETFL, O_NONBLOCK);
-		address.sin_family = AF_INET;
-
-		status = g_strdup_printf(_("LOOKING UP %s"), chost);
-		flac_ip.set_info_text(status);
-		g_free(status);
-
-		if (!(hp = gethostbyname(chost)))
-		{
-			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
-			show_error_message(status);
-			g_free(status);
-
-			flac_ip.set_info_text(NULL);
-			eof = TRUE;
-		}
-
-		if (!eof)
-		{
-			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
-			address.sin_port = (gint) g_htons(cport);
-
-			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
-			flac_ip.set_info_text(status);
-			g_free(status);
-			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
-			{
-				if (errno != EINPROGRESS)
-				{
-					status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
-					show_error_message(status);
-					g_free(status);
-
-					flac_ip.set_info_text(NULL);
-					eof = TRUE;
-				}
-			}
-			while (going)
-			{
-				tv.tv_sec = 0;
-				tv.tv_usec = 10000;
-				FD_ZERO(&set);
-				FD_SET(sock, &set);
-				if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
-				{
-					err_len = sizeof (error);
-					getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
-					if (error)
-					{
-						status = g_strdup_printf(_("Couldn't connect to host %s"),
-									 chost);
-						show_error_message(status);
-						g_free(status);
-
-						flac_ip.set_info_text(NULL);
-						eof = TRUE;
-						
-					}
-					break;
-				}
-			}
-			if (!eof)
-			{
-				gchar *auth = NULL, *proxy_auth = NULL;
-				gchar udpspace[30];
-				int udp_port;
-
-				if (flac_cfg.stream.use_udp_channel)
-				{
-					udp_port = udp_establish_listener (&udp_sock);
-					if (udp_port > 0) 
-						sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port);
-					else
-						udp_sock = 0;
-				}
-					
-				if(user && pass)
-					auth = basic_authentication_encode(user, pass, "Authorization");
-
-				if (flac_cfg.stream.use_proxy)
-				{
-					file = g_strdup(url);
-					if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
-					{
-						proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
-											 flac_cfg.stream.proxy_pass,
-											 "Proxy-Authorization");
-					}
-				}
-				else
-					file = g_strconcat("/", filename, NULL);
-
-				temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
-						       "Host: %s\r\n"
-						       "User-Agent: %s/%s\r\n"
-						       "%s%s%s%s",
-						       file, host, "Reference FLAC Player", FLAC__VERSION_STRING, 
-						       proxy_auth ? proxy_auth : "", auth ? auth : "",
-						       flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
-						       flac_cfg.stream.use_udp_channel ? udpspace : "");
-				if (offset && !head) {
-					gchar *temp_dead = temp;
-					temp = g_strconcat ("%sRange: %ll-\r\n", temp, offset, NULL);
-					fprintf (stderr, "%s", temp);
-					g_free (temp_dead);
-				}
-				
-				g_free(file);
-				if(proxy_auth)
-					g_free(proxy_auth);
-				if(auth)
-					g_free(auth);
-				write(sock, temp, strlen(temp));
-				write(sock, "\r\n", 2);
-				g_free(temp);
-				flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
-				while (going && !eof)
-				  {
-					if (http_check_for_data())
-					{
-						if (flac_http_read_line(line, 1024))
-						{
-							status = strchr(line, ' ');
-							if (status)
-							{
-								if (status[1] == '2')
-									break;
-								else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
-								{
-									while(going)
-									{
-										if(http_check_for_data())
-										{
-											if((cnt = flac_http_read_line(line, 1024)) != -1)
-											{
-												if(!cnt)
-													break;
-												if(!strncmp(line, "Location:", 9))
-												{
-													g_free(url);
-													url = g_strdup(line+10);
-												}
-											}
-											else
-											{
-												eof=TRUE;
-												flac_ip.set_info_text(NULL);
-												break;
-											}
-										}
-									}			
-									redirect=TRUE;
-									break;
-								}
-								else
-								{
-									status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
-									show_error_message(status);
-									g_free(status);
-									break;
-								}
-							}
-						}
-						else
-						{
-							eof = TRUE;
-							flac_ip.set_info_text(NULL);
-						}
-					}
-				}
-
-				while (going && !redirect)
-				{
-					if (http_check_for_data())
-					{
-						if ((cnt = flac_http_read_line(line, 1024)) != -1)
-						{
-							if (!cnt)
-								break;
-							if (!strncmp(line, "icy-name:", 9))
-								icy_name = g_strdup(line + 9);
-							else if (!strncmp(line, "x-audiocast-name:", 17))
-								icy_name = g_strdup(line + 17);
-							if (!strncmp(line, "icy-metaint:", 12))
-								icy_metaint = atoi(line + 12);
-							if (!strncmp(line, "x-audiocast-udpport:", 20)) {
-#ifdef DEBUG_UDP
-								fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
-#endif
-								/*udp_serverport = atoi (line + 20);*/
-							}
-							
-						}
-						else
-						{
-							eof = TRUE;
-							flac_ip.set_info_text(NULL);
-							break;
-						}
-					}
-				}
-			}
-		}
-	
-		if(redirect)
-		{
-			if (output_file)
-			{
-				fclose(output_file);
-				output_file = NULL;
-			}
-			close(sock);
-		}
-
-		g_free(user);
-		g_free(pass);
-		g_free(host);
-		g_free(filename);
-	} while(redirect);
-
-	g_free(url);
-	return eof ? -1 : sock;
-}
-
-static void *http_buffer_loop(void *arg)
-{
-	gchar *status, *url, *temp, *file;
-	gint cnt, written;
-	int udp_sock = 0;
-
-	url = (gchar *) arg;
-	sock = http_connect (url, false, offset);
-	
-	if (sock >= 0 && flac_cfg.stream.save_http_stream) {
-		gchar *output_name;
-		file = flac_http_get_title(url);
-		output_name = file;
-		if (!strncasecmp(output_name, "http://", 7))
-			output_name += 7;
-		temp = strrchr(output_name, '.');
-		if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
-			*temp = '\0';
-
-		while ((temp = strchr(output_name, '/')))
-			*temp = '_';
-		output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
-
-		g_free(file);
-
-		output_file = fopen(output_name, "wb");
-		g_free(output_name);
-	}
-
-	while (going)
-	{
-
-		if (!http_used() && !flac_ip.output->buffer_playing())
-		{
-			prebuffering = TRUE;
-			flac_ip.set_status_buffering(TRUE);
-		}
-		if (http_free() > 0 && !eof)
-		{
-			if (http_check_for_data())
-			{
-				cnt = min(http_free(), buffer_length - wr_index);
-				if (cnt > 1024)
-					cnt = 1024;
-				written = read(sock, buffer + wr_index, cnt);
-				if (written <= 0)
-				{
-					eof = TRUE;
-					if (prebuffering)
-					{
-						prebuffering = FALSE;
-						flac_ip.set_status_buffering(FALSE);
-
-						flac_ip.set_info_text(NULL);
-					}
-
-				}
-				else
-					wr_index = (wr_index + written) % buffer_length;
-			}
-
-			if (prebuffering)
-			{
-				if (http_used() > prebuffer_length)
-				{
-					prebuffering = FALSE;
-					flac_ip.set_status_buffering(FALSE);
-					flac_ip.set_info_text(NULL);
-				}
-				else
-				{
-					status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
-					flac_ip.set_info_text(status);
-					g_free(status);
-				}
-
-			}
-		}
-		else
-			xmms_usleep(10000);
-
-		if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
-			if (udp_check_for_data(udp_sock) < 0)
-			{
-				close(udp_sock);
-				udp_sock = 0;
-			}
-	}
-	if (output_file)
-	{
-		fclose(output_file);
-		output_file = NULL;
-	}
-	if (sock >= 0) {
-		close(sock);
-	}
-	if (udp_sock != 0)
-		close(udp_sock);
-
-	g_free(buffer);
-	g_free(url);
-	
-	g_thread_exit(NULL);
-	return NULL; /* avoid compiler warning */
-}
-
-int flac_http_open(gchar * _url, guint64 _offset)
-{
-	gchar *url;
-
-	url = g_strdup(_url);
-
-	rd_index = 0;
-	wr_index = 0;
-	buffer_length = flac_cfg.stream.http_buffer_size * 1024;
-	prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
-	buffer_read = 0;
-	icy_metaint = 0;
-	prebuffering = TRUE;
-	flac_ip.set_status_buffering(TRUE);
-	going = TRUE;
-	eof = FALSE;
-	buffer = g_malloc(buffer_length);
-	offset = _offset;
-
-	thread = g_thread_create((GThreadFunc)http_buffer_loop, url, TRUE, NULL);
-
-	return 0;
-}
-
-char *flac_http_get_title(char *url)
-{
-	if (icy_name)
-		return g_strdup(icy_name);
-	if (g_basename(url) && strlen(g_basename(url)) > 0)
-		return g_strdup(g_basename(url));
-	return g_strdup(url);
-}
-
-/* Start UDP Channel specific stuff */
-
-/* Find a good local udp port and bind udp_sock to it, return the port */
-static int udp_establish_listener(int *sock)
-{
-	struct sockaddr_in sin;
-	socklen_t sinlen = sizeof (struct sockaddr_in);
-	
-#ifdef DEBUG_UDP
-	fprintf (stderr,"Establishing udp listener\n");
-#endif
-	
-	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-	{
-		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener(): unable to create socket");
-		return -1;
-	}
-
-	memset(&sin, 0, sinlen);
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
-			
-	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
-	{
-		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
-		close(*sock);
-		return -1;
-	}
-	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
-	{
-		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
-		close(*sock);
-		return -1;
-	}
-
-	memset(&sin, 0, sinlen);
-	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
-	{
-		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
-		close(*sock);
-		return -1;
-	}
-
-#ifdef DEBUG_UDP
-	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
-#endif
-	
-	return g_ntohs(sin.sin_port);
-}
-
-static int udp_check_for_data(int sock)
-{
-	char buf[1025], **lines;
-	char *valptr;
-	gchar *title;
-	gint len, i;
-	struct sockaddr_in from;
-	socklen_t fromlen;
-
-	fromlen = sizeof(struct sockaddr_in);
-	
-	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
-	{
-		if (errno != EAGAIN)
-		{
-			g_log(NULL, G_LOG_LEVEL_CRITICAL,
-			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
-			return -1;
-		}
-		return 0;
-	}
-	buf[len] = '\0';
-#ifdef DEBUG_UDP
-	fprintf (stderr,"Received: [%s]\n", buf);
-#endif
-	lines = g_strsplit(buf, "\n", 0);
-	if (!lines)
-		return 0;
-	
-	for (i = 0; lines[i]; i++)
-	{
-		while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
-		       (lines[i][strlen(lines[i]) - 1] == '\r'))
-			lines[i][strlen(lines[i]) - 1] = '\0';
-		
-		valptr = strchr(lines[i], ':');
-		
-		if (!valptr)
-			continue;
-		else
-			valptr++;
-		
-		g_strstrip(valptr);
-		if (!strlen(valptr))
-			continue;
-		
-		if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
-		{
-			title = g_strdup_printf ("%s (%s)", valptr, icy_name);
-			if (going)
-				set_track_info(title, -1);
-			g_free (title);
-		}
-
-#if 0
-		else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
-		{
-			if (atoi(valptr) != -1)
-				set_track_info(NULL, atoi(valptr));
-		}
-#endif
-				
-		else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
-		{
-			/* set_track_info(title, -1); */
-/*  			xmms_show_message(_("Message"), valptr, _("Ok"), */
-/*  					  FALSE, NULL, NULL); */
-			g_message("Stream_message: %s", valptr);
-		}
-
-#if 0
-		/* Use this to direct your webbrowser.. yeah right.. */
-		else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
-		{
-			if (lasturl && g_strcmp (valptr, lasturl))
-			{
-				c_message (stderr, "Song URL: %s\n", valptr);
-				g_free (lasturl);
-				lasturl = g_strdup (valptr);
-			}
-		}
-#endif
-		else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
-		{
-			gchar obuf[60];
-			sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr));
-			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
-			{
-				g_log(NULL, G_LOG_LEVEL_WARNING,
-				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
-			}
-#ifdef DEBUG_UDP
-			else
-				fprintf(stderr,"Sent ack: %s", obuf);
-			fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
-#endif
-		}
-	}
-	g_strfreev(lines);
-	return 0;
-}
--- a/src/flac/http.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef __HTTP_H__
-#define __HTTP_H__
-
-extern int flac_http_open(gchar * url, guint64 offset);
-extern void flac_http_close(void);
-extern int flac_http_read(gpointer data, gint length);
-
-
-#endif
--- a/src/flac/plugin.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,718 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2000,2001,2002,2003,2004,2005,2006  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <glib.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "audacious/plugin.h"
-#include "audacious/output.h"
-#include "audacious/util.h"
-#include "audacious/configdb.h"
-#include "audacious/titlestring.h"
-#include "audacious/vfs.h"
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_LANGINFO_CODESET
-#include <langinfo.h>
-#endif
-
-#include "FLAC/all.h"
-#include "plugin_common/all.h"
-#include "grabbag.h"
-#include "replaygain_synthesis.h"
-#include "configure.h"
-#include "charset.h"
-#include "http.h"
-#include "tag.h"
-
-#ifdef min
-#undef min
-#endif
-#define min(x,y) ((x)<(y)?(x):(y))
-
-extern void FLAC_XMMS__file_info_box(char *filename);
-
-typedef struct {
-	FLAC__bool abort_flag;
-	FLAC__bool is_playing;
-	FLAC__bool is_http_source;
-	FLAC__bool eof;
-	FLAC__bool play_thread_open; /* if true, is_playing must also be true */
-	FLAC__uint64 total_samples;
-	unsigned bits_per_sample;
-	unsigned channels;
-	unsigned sample_rate;
-	int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */
-	gchar *title;
-	AFormat sample_format;
-	unsigned sample_format_bytes_per_sample;
-	int seek_to_in_sec;
-	FLAC__bool has_replaygain;
-	double replay_scale;
-	DitherContext dither_context;
-} stream_data_struct;
-
-static void FLAC_XMMS__init();
-static int  FLAC_XMMS__is_our_file(char *filename);
-static void FLAC_XMMS__play_file(char *filename);
-static void FLAC_XMMS__stop();
-static void FLAC_XMMS__pause(short p);
-static void FLAC_XMMS__seek(int time);
-static int  FLAC_XMMS__get_time();
-static void FLAC_XMMS__cleanup();
-static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
-
-static void *play_loop_(void *arg);
-
-static FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder);
-static void safe_decoder_finish_(FLAC__StreamDecoder *decoder);
-static void safe_decoder_delete_(FLAC__StreamDecoder *decoder);
-
-static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
-static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
-static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
-
-InputPlugin flac_ip =
-{
-	NULL,
-	NULL,
-	NULL,
-	FLAC_XMMS__init,
-	FLAC_XMMS__aboutbox,
-	FLAC_XMMS__configure,
-	FLAC_XMMS__is_our_file,
-	NULL,
-	FLAC_XMMS__play_file,
-	FLAC_XMMS__stop,
-	FLAC_XMMS__pause,
-	FLAC_XMMS__seek,
-	NULL,
-	FLAC_XMMS__get_time,
-	NULL,
-	NULL,
-	FLAC_XMMS__cleanup,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	FLAC_XMMS__get_song_info,
-	FLAC_XMMS__file_info_box,
-	NULL,
-	flac_get_tuple
-};
-
-#define SAMPLES_PER_WRITE 512
-#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8))
-static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE];
-static unsigned sample_buffer_first_, sample_buffer_last_;
-
-static FLAC__StreamDecoder *decoder_ = 0, *decoder2 = 0;
-static stream_data_struct stream_data_;
-static GThread *decode_thread_;
-static FLAC__bool audio_error_ = false;
-static FLAC__bool is_big_endian_host_;
-
-#define BITRATE_HIST_SEGMENT_MSEC 500
-/* 500ms * 50 = 25s should be enough */
-#define BITRATE_HIST_SIZE 50
-static unsigned bitrate_history_[BITRATE_HIST_SIZE];
-
-#ifdef SUPPORT_ATTRIBUTE_VISIBILITY
-InputPlugin *get_iplugin_info() __attribute__((visibility("default")));
-#endif
-
-InputPlugin *get_iplugin_info()
-{
-	flac_ip.description = g_strdup_printf(_("FLAC Audio Plugin"));
-	return &flac_ip;
-}
-
-void set_track_info(const char* title, int length_in_msec)
-{
-	if (stream_data_.is_playing) {
-		flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
-	}
-}
-
-static gchar* homedir()
-{
-	gchar *result;
-	char *env_home = getenv("HOME");
-	if (env_home) {
-		result = g_strdup (env_home);
-	} else {
-		uid_t uid = getuid();
-		struct passwd *pwent;
-		do {
-			pwent = getpwent();
-		} while (pwent && pwent->pw_uid != uid);
-		result = pwent ? g_strdup (pwent->pw_dir) : NULL;
-		endpwent();
-	}
-	return result;
-}
-
-static FLAC__bool is_http_source(const char *source)
-{
-	return 0 == strncasecmp(source, "http://", 7);
-}
-
-void FLAC_XMMS__init()
-{
-	ConfigDb *db;
-	FLAC__uint32 test = 1;
-	gchar *tmp;
-
-	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
-
-	flac_cfg.title.tag_override = FALSE;
-	if (flac_cfg.title.tag_format)
-		g_free(flac_cfg.title.tag_format);
-	flac_cfg.title.convert_char_set = FALSE;
-
-	db = bmp_cfg_db_open();
-
-	/* title */
-
-	bmp_cfg_db_get_bool(db, "flac", "title.tag_override", &flac_cfg.title.tag_override);
-
-	if(!bmp_cfg_db_get_string(db, "flac", "title.tag_format", &flac_cfg.title.tag_format))
-		flac_cfg.title.tag_format = g_strdup("%p - %t");
-
-	bmp_cfg_db_get_bool(db, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set);
-
-	if(!bmp_cfg_db_get_string(db, "flac", "title.user_char_set", &flac_cfg.title.user_char_set))
-		flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current();
-
-	/* replaygain */
-
-	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable);
-
-	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode);
-
-	if(!bmp_cfg_db_get_int(db, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp))
-		flac_cfg.output.replaygain.preamp = 0;
-
-	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit);
-
-	bmp_cfg_db_get_bool(db, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16);
-	bmp_cfg_db_get_bool(db, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither);
-
-	if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping))
-		flac_cfg.output.resolution.replaygain.noise_shaping = 1;
-
-	if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out))
-		flac_cfg.output.resolution.replaygain.bps_out = 16;
-
-	/* stream */
-
-	bmp_cfg_db_get_int(db, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size);
-	bmp_cfg_db_get_int(db, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer);
-	bmp_cfg_db_get_bool(db, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream);
-	if (!bmp_cfg_db_get_string(db, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) ||
-		 ! *flac_cfg.stream.save_http_path) {
-	  /* TODO: Is this a memory leak ?? */
-	  /*
-		if (flac_cfg.stream.save_http_path)
-			g_free (flac_cfg.stream.save_http_path);
-	  */
-		flac_cfg.stream.save_http_path = homedir();
-	}
-	bmp_cfg_db_get_bool(db, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming);
-	bmp_cfg_db_get_bool(db, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel);
-
-	bmp_cfg_db_get_bool(db, NULL, "use_proxy", &flac_cfg.stream.use_proxy);
-	bmp_cfg_db_get_string(db, NULL, "proxy_host", &flac_cfg.stream.proxy_host);
-	bmp_cfg_db_get_string(db, NULL, "proxy_port", &tmp);
-
-	bmp_cfg_db_get_bool(db, NULL, "proxy_use_auth", &flac_cfg.stream.proxy_use_auth);
-	bmp_cfg_db_get_string(db, NULL, "proxy_user", &flac_cfg.stream.proxy_user);
-	bmp_cfg_db_get_string(db, NULL, "proxy_pass", &flac_cfg.stream.proxy_pass);
-
-	decoder_ = FLAC__stream_decoder_new();
-	bmp_cfg_db_close(db);
-}
-
-int FLAC_XMMS__is_our_file(char *filename)
-{
-	FILE *f;
-	FLAC__StreamMetadata streaminfo;
-
-	if(!is_http_source(filename)) {
-		if(0 == (f = fopen(filename, "r")))
-			return 0;
-		fclose(f);
-		if(FLAC__metadata_get_streaminfo(filename, &streaminfo))
-			return 1;
-		return 0;
-	}
-
-	if(!safe_decoder_init_(filename, decoder2))
-		return 0;
-
-	safe_decoder_finish_(decoder2);   
-	return 1;
-}
-
-void FLAC_XMMS__play_file(char *filename)
-{
-	FILE *f;
-
-	sample_buffer_first_ = sample_buffer_last_ = 0;
-	audio_error_ = false;
-	stream_data_.abort_flag = false;
-	stream_data_.is_playing = false;
-	stream_data_.is_http_source = is_http_source(filename);
-	stream_data_.eof = false;
-	stream_data_.play_thread_open = false;
-	stream_data_.has_replaygain = false;
-
-	if(!is_http_source(filename)) {
-		if(0 == (f = fopen(filename, "r")))
-			return;
-		fclose(f);
-	}
-
-	if(decoder_ == 0)
-		return;
-
-	if(!safe_decoder_init_(filename, decoder_))
-		return;
-
-	if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) {
-		if(flac_cfg.output.resolution.replaygain.bps_out == 8) {
-			stream_data_.sample_format = FMT_U8;
-			stream_data_.sample_format_bytes_per_sample = 1;
-		}
-		else if(flac_cfg.output.resolution.replaygain.bps_out == 16) {
-			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
-			stream_data_.sample_format_bytes_per_sample = 2;
-		}
-		else {
-			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
-			fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out);
-			safe_decoder_finish_(decoder_);
-			return;
-		}
-	}
-	else {
-		if(stream_data_.bits_per_sample == 8) {
-			stream_data_.sample_format = FMT_U8;
-			stream_data_.sample_format_bytes_per_sample = 1;
-		}
-		else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) {
-			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
-			stream_data_.sample_format_bytes_per_sample = 2;
-		}
-		else {
-			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
-			fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", stream_data_.bits_per_sample);
-			safe_decoder_finish_(decoder_);
-			return;
-		}
-	}
-	FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping);
-	stream_data_.is_playing = true;
-
-	if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) {
-		audio_error_ = true;
-		safe_decoder_finish_(decoder_);
-		return;
-	}
-
-	stream_data_.title = flac_format_song_title(filename);
-	flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
-
-	stream_data_.seek_to_in_sec = -1;
-	stream_data_.play_thread_open = true;
-	decode_thread_ = g_thread_create((GThreadFunc)play_loop_, NULL, TRUE, NULL);
-}
-
-void FLAC_XMMS__stop()
-{
-	if(stream_data_.is_playing) {
-		stream_data_.is_playing = false;
-		if(stream_data_.play_thread_open) {
-			stream_data_.play_thread_open = false;
-			g_thread_join(decode_thread_);
-		}
-		flac_ip.output->close_audio();
-		safe_decoder_finish_(decoder_);
-	}
-}
-
-void FLAC_XMMS__pause(short p)
-{
-	flac_ip.output->pause(p);
-}
-
-void FLAC_XMMS__seek(int time)
-{
-	if(!stream_data_.is_http_source) {
-		stream_data_.seek_to_in_sec = time;
-		stream_data_.eof = false;
-
-		while(stream_data_.seek_to_in_sec != -1)
-			xmms_usleep(10000);
-	}
-}
-
-int FLAC_XMMS__get_time()
-{
-	if(audio_error_)
-		return -2;
-	if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing()))
-		return -1;
-	else
-		return flac_ip.output->output_time();
-}
-
-void FLAC_XMMS__cleanup()
-{
-    g_free(flac_ip.description);
-    flac_ip.description = NULL;
-
-    if (flac_cfg.title.tag_format) {
-        free(flac_cfg.title.tag_format);
-        flac_cfg.title.tag_format = NULL;
-    }
-
-    if (flac_cfg.title.user_char_set) {
-        free(flac_cfg.title.user_char_set);
-        flac_cfg.title.user_char_set = NULL;
-    }
-
-    if (flac_cfg.stream.proxy_host) {
-        free(flac_cfg.stream.proxy_host);
-        flac_cfg.stream.proxy_host = NULL;
-    }
-
-    if (flac_cfg.stream.proxy_user) {
-        free(flac_cfg.stream.proxy_user);
-        flac_cfg.stream.proxy_user = NULL;
-
-    }
-
-    if (flac_cfg.stream.proxy_pass) {
-        free(flac_cfg.stream.proxy_pass);
-        flac_cfg.stream.proxy_pass = NULL;
-    }
-
-	safe_decoder_delete_(decoder_);
-	decoder_ = 0;
-}
-
-void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
-{
-	FLAC__StreamMetadata streaminfo;
-
-	if(0 == filename)
-		filename = "";
-
-	if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
-		/* @@@ how to report the error? */
-		if(title) {
-			if (!is_http_source(filename)) {
-				static const char *errtitle = "Invalid FLAC File: ";
-				*title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1);
-				sprintf(*title, "%s\"%s\"", errtitle, filename);
-			} else {
-				*title = NULL;
-			}
-		}
-		if(length_in_msec)
-			*length_in_msec = -1;
-		return;
-	}
-
-	if(title) {
-		*title = flac_format_song_title(filename);
-	}
-	if(length_in_msec) {
-		FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
-		if (l > INT_MAX)
-			l = INT_MAX;
-		*length_in_msec = (int)l;
-	}
-}
-
-/***********************************************************************
- * local routines
- **********************************************************************/
-
-void *play_loop_(void *arg)
-{
-	unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1;
-	FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0;
-
-	(void)arg;
-
-	while(stream_data_.is_playing) {
-		if(!stream_data_.eof) {
-			while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) {
-				unsigned s;
-
-				s = sample_buffer_last_ - sample_buffer_first_;
-				if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) {
-					stream_data_.eof = true;
-					break;
-				}
-				else if(!FLAC__stream_decoder_process_single(decoder_)) {
-					/*@@@ this should probably be a dialog */
-					fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n");
-					stream_data_.eof = true;
-					break;
-				}
-				blocksize = sample_buffer_last_ - sample_buffer_first_ - s;
-				decode_position_frame_last = decode_position_frame;
-				if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
-					decode_position_frame = 0;
-			}
-			if(sample_buffer_last_ - sample_buffer_first_ > 0) {
-				const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE);
-				int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
-				FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
-				unsigned written_time, bh_index_w;
-				FLAC__uint64 decode_position;
-
-				sample_buffer_first_ += n;
-				while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
-					xmms_usleep(10000);
-				if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
-					produce_audio(flac_ip.output->written_time(), stream_data_.sample_format,
-						stream_data_.channels, bytes, sample_buffer_start, NULL);
-
-				/* compute current bitrate */
-
-				written_time = flac_ip.output->written_time();
-				bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
-				if(bh_index_w != bh_index_last_w) {
-					bh_index_last_w = bh_index_w;
-					decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize;
-					bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] =
-						decode_position > decode_position_last && written_time > written_time_last ?
-							8000 * (decode_position - decode_position_last) / (written_time - written_time_last) :
-							stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample;
-					decode_position_last = decode_position;
-					written_time_last = written_time;
-				}
-			}
-			else {
-				stream_data_.eof = true;
-				xmms_usleep(10000);
-			}
-		}
-		else
-			xmms_usleep(10000);
-		if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) {
-			const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec;
-			FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples);
-			if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples)
-				target_sample = stream_data_.total_samples - 1;
-			if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) {
-				flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000);
-				bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
-				if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
-					decode_position_frame = 0;
-				stream_data_.eof = false;
-				sample_buffer_first_ = sample_buffer_last_ = 0;
-			}
-			else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) {
-				/*@@@ this should probably be a dialog */
-				fprintf(stderr, "libxmms-flac: SEEK ERROR\n");
-				FLAC__stream_decoder_flush(decoder_);
-				stream_data_.eof = false;
-				sample_buffer_first_ = sample_buffer_last_ = 0;
-			}
-			stream_data_.seek_to_in_sec = -1;
-		}
-		else {
-			/* display the right bitrate from history */
-			unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
-			if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) {
-				bh_index_last_o = bh_index_o;
-				flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels);
-			}
-		}
-	}
-
-	safe_decoder_finish_(decoder_);
-
-	/* are these two calls necessary? */
-	flac_ip.output->buffer_free();
-	flac_ip.output->buffer_free();
-
-	g_free(stream_data_.title);
-
-	g_thread_exit(NULL);
-	return 0; /* to silence the compiler warning about not returning a value */
-}
-
-FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder)
-{
-	if(decoder == 0)
-		return false;
-
-	safe_decoder_finish_(decoder);
-
-	FLAC__stream_decoder_set_md5_checking(decoder, false);
-	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
-	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
-	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	if(stream_data_.is_http_source) {
-		flac_http_open(filename, 0);
-		if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
-			return false;
-	}
-	else {
-		if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
-			return false;
-	}
-
-	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
-		return false;
-
-	return true;
-}
-
-void safe_decoder_finish_(FLAC__StreamDecoder *decoder)
-{
-	if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED)
-		FLAC__stream_decoder_finish(decoder);
-	if(stream_data_.is_http_source)
-		flac_http_close();
-}
-
-void safe_decoder_delete_(FLAC__StreamDecoder *decoder)
-{
-	if(decoder) {
-		safe_decoder_finish_(decoder);
-		FLAC__stream_decoder_delete(decoder);
-	}
-}
-
-FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
-{
-	(void)decoder;
-	(void)client_data;
-	*bytes = flac_http_read(buffer, *bytes);
-	return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
-}
-
-FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
-{
-	stream_data_struct *stream_data = (stream_data_struct *)client_data;
-	const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize;
-	const unsigned bits_per_sample = stream_data->bits_per_sample;
-	FLAC__byte *sample_buffer_start;
-
-	(void)decoder;
-
-	if(stream_data->abort_flag)
-		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-
-	if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) {
-		memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample);
-		sample_buffer_last_ -= sample_buffer_first_;
-		sample_buffer_first_ = 0;
-	}
-	sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample;
-	if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) {
-		FLAC__replaygain_synthesis__apply_gain(
-				sample_buffer_start,
-				!is_big_endian_host_,
-				stream_data->sample_format_bytes_per_sample == 1, /* unsigned_data_out */
-				buffer,
-				wide_samples,
-				channels,
-				bits_per_sample,
-				stream_data->sample_format_bytes_per_sample * 8,
-				stream_data->replay_scale,
-				flac_cfg.output.replaygain.hard_limit,
-				flac_cfg.output.resolution.replaygain.dither,
-				&stream_data->dither_context
-		);
-	}
-	else if(is_big_endian_host_) {
-		FLAC__plugin_common__pack_pcm_signed_big_endian(
-			sample_buffer_start,
-			buffer,
-			wide_samples,
-			channels,
-			bits_per_sample,
-			stream_data->sample_format_bytes_per_sample * 8
-		);
-	}
-	else {
-		FLAC__plugin_common__pack_pcm_signed_little_endian(
-			sample_buffer_start,
-			buffer,
-			wide_samples,
-			channels,
-			bits_per_sample,
-			stream_data->sample_format_bytes_per_sample * 8
-		);
-	}
-
-	sample_buffer_last_ += wide_samples;
-
-	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
-{
-	stream_data_struct *stream_data = (stream_data_struct *)client_data;
-	(void)decoder;
-	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
-		stream_data->total_samples = metadata->data.stream_info.total_samples;
-		stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample;
-		stream_data->channels = metadata->data.stream_info.channels;
-		stream_data->sample_rate = metadata->data.stream_info.sample_rate;
-		{
-			FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5);
-			if (l > INT_MAX)
-				l = INT_MAX;
-			stream_data->length_in_msec = (int)l;
-		}
-	}
-	else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
-		double reference, gain, peak;
-		if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) {
-			stream_data->has_replaygain = true;
-			stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit);
-		}
-	}
-}
-
-void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
-{
-	stream_data_struct *stream_data = (stream_data_struct *)client_data;
-	(void)decoder;
-	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
-		stream_data->abort_flag = true;
-}
--- a/src/flac/plugin.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__PLUGIN_XMMS__PLUGIN_H
-#define FLAC__PLUGIN_XMMS__PLUGIN_H
-
-void set_track_info(const char* title, int length_in_msec);
-
-#endif
--- a/src/flac/plugin_common/Makefile	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-include ../../../mk/rules.mk
-include ../../../mk/init.mk
-
-CFLAGS += $(PICFLAGS) -I.. -I../../..
-
-OBJECTIVE_LIBS_NOINST = libplugin_common.a
-
-noinst_HEADERS = \
-	all.h \
-	charset.h \
-	defs.h \
-	dither.h \
-	locale_hack.h \
-	tags.h \
-	replaygain.h
-
-SOURCES = \
-	charset.c \
-	dither.c \
-	tags.c \
-	replaygain.c
-
-OBJECTS = ${SOURCES:.c=.o}
-
-libplugin_common.a: $(OBJECTS)
-	$(AR) cq $@ $(OBJECTS)
-
-include ../../../mk/objective.mk
--- a/src/flac/plugin_common/all.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__PLUGIN_COMMON__ALL_H
-#define FLAC__PLUGIN_COMMON__ALL_H
-
-#include "charset.h"
-#include "dither.h"
-#include "locale_hack.h"
-#include "tags.h"
-
-#endif
--- a/src/flac/plugin_common/charset.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * Only slightly modified charset.c from:
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_ICONV
-#include <iconv.h>
-#endif
-
-#ifdef HAVE_LANGINFO_CODESET
-#include <langinfo.h>
-#endif
-
-#include "charset.h"
-
-
-/*************
- * Functions *
- *************/
-
-char* FLAC_plugin__charset_get_current (void)
-{
-	char *charset = getenv("CHARSET");
-
-#ifdef HAVE_LANGINFO_CODESET
-	if (!charset)
-		charset = nl_langinfo(CODESET);
-#endif
-
-    if (charset)
-        return strdup(charset);
-
-    return strdup("ISO-8859-1");
-}
-
-
-#ifdef HAVE_ICONV
-char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
-{
-	size_t outleft, outsize, length;
-	iconv_t cd;
-	char *out, *outptr;
-	const char *input = string;
-
-	if (!string)
-		return NULL;
-
-	length = strlen(string);
-
-	if ((cd = iconv_open(to, from)) == (iconv_t)-1)
-	{
-#ifdef DEBUG
-		fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to);
-#endif
-		return strdup(string);
-	}
-
-	/* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */
-	/* + 1 for nul in case len == 1 */
-	outsize = ((length + 3) & ~3) + 1;
-	out = (char*)malloc(outsize);
-	outleft = outsize - 1;
-	outptr = out;
-
-retry:
-#if defined __OpenBSD__ || defined __NetBSD__
-	if (iconv(cd, &input, &length, &outptr, &outleft) == (size_t)-1)
-#else
-	if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)-1)
-#endif
-	{
-		int used;
-		switch (errno)
-		{
-			case E2BIG:
-				used = outptr - out;
-				outsize = (outsize - 1) * 2 + 1;
-				out = realloc(out, outsize);
-				outptr = out + used;
-				outleft = outsize - 1 - used;
-				goto retry;
-			case EINVAL:
-				break;
-			case EILSEQ:
-				/* Invalid sequence, try to get the rest of the string */
-				input++;
-				length = strlen(input);
-				goto retry;
-			default:
-#ifdef DEBUG
-				fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno));
-#endif
-				break;
-		}
-	}
-	*outptr = '\0';
-
-	iconv_close(cd);
-	return out;
-}
-#else
-char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
-{
-	(void)from, (void)to;
-	if (!string)
-		return NULL;
-	return strdup(string);
-}
-#endif
-
-#ifdef HAVE_ICONV
-int FLAC_plugin__charset_test_conversion (char *from, char *to)
-{
-	iconv_t cd;
-
-	if ((cd=iconv_open(to,from)) == (iconv_t)-1)
-	{
-		/* Conversion not supported */
-		return 0;
-	}
-	iconv_close(cd);
-	return 1;
-}
-#else
-int FLAC_plugin__charset_test_conversion (char *from, char *to)
-{
-	(void)from, (void)to;
-	return 1;
-}
-#endif
--- a/src/flac/plugin_common/charset.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * Only slightly modified charset.h from:
- * charset.h - 2001/12/04
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-
-#ifndef FLAC__PLUGIN_COMMON__CHARSET_H
-#define FLAC__PLUGIN_COMMON__CHARSET_H
-
-
-/**************
- * Prototypes *
- **************/
-
-char *FLAC_plugin__charset_get_current();
-char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to);
-
-/* returns 1 for success, 0 for failure or no iconv */
-int FLAC_plugin__charset_test_conversion(char *from, char *to);
-
-#endif
--- a/src/flac/plugin_common/defs.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__PLUGIN_COMMON__DEFS_H
-#define FLAC__PLUGIN_COMMON__DEFS_H
-
-#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2
-
-#endif
--- a/src/flac/plugin_common/dither.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,260 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * dithering routine derived from (other GPLed source):
- * mad - MPEG audio decoder
- * Copyright (C) 2000-2001 Robert Leslie
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include "dither.h"
-#include "FLAC/assert.h"
-
-#ifdef max
-#undef max
-#endif
-#define max(a,b) ((a)>(b)?(a):(b))
-
-
-#if defined _MSC_VER
-#define FLAC__INLINE __inline
-#else
-#define FLAC__INLINE
-#endif
-
-/* 32-bit pseudo-random number generator
- *
- * @@@ According to Miroslav, this one is poor quality, the one from the
- * @@@ original replaygain code is much better
- */
-static FLAC__INLINE FLAC__uint32 prng(FLAC__uint32 state)
-{
-	return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
-}
-
-/* dither routine derived from MAD winamp plugin */
-
-typedef struct {
-	FLAC__int32 error[3];
-	FLAC__int32 random;
-} dither_state;
-
-static FLAC__INLINE FLAC__int32 linear_dither(unsigned source_bps, unsigned target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX)
-{
-	unsigned scalebits;
-	FLAC__int32 output, mask, random;
-
-	FLAC__ASSERT(source_bps < 32);
-	FLAC__ASSERT(target_bps <= 24);
-	FLAC__ASSERT(target_bps <= source_bps);
-
-	/* noise shape */
-	sample += dither->error[0] - dither->error[1] + dither->error[2];
-
-	dither->error[2] = dither->error[1];
-	dither->error[1] = dither->error[0] / 2;
-
-	/* bias */
-	output = sample + (1L << (source_bps - target_bps - 1));
-
-	scalebits = source_bps - target_bps;
-	mask = (1L << scalebits) - 1;
-
-	/* dither */
-	random = (FLAC__int32)prng(dither->random);
-	output += (random & mask) - (dither->random & mask);
-
-	dither->random = random;
-
-	/* clip */
-	if(output > MAX) {
-		output = MAX;
-
-		if(sample > MAX)
-			sample = MAX;
-	}
-	else if(output < MIN) {
-		output = MIN;
-
-		if(sample < MIN)
-			sample = MIN;
-	}
-
-	/* quantize */
-	output &= ~mask;
-
-	/* error feedback */
-	dither->error[0] = sample - output;
-
-	/* scale */
-	return output >> scalebits;
-}
-
-size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
-{
-	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
-	FLAC__byte * const start = data;
-	FLAC__int32 sample;
-	const FLAC__int32 *input_;
-	unsigned samples, channel;
-	const unsigned bytes_per_sample = target_bps / 8;
-	const unsigned incr = bytes_per_sample * channels;
-
-	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
-	FLAC__ASSERT(source_bps < 32);
-	FLAC__ASSERT(target_bps <= 24);
-	FLAC__ASSERT(target_bps <= source_bps);
-	FLAC__ASSERT((source_bps & 7) == 0);
-	FLAC__ASSERT((target_bps & 7) == 0);
-
-	if(source_bps != target_bps) {
-		const FLAC__int32 MIN = -(1L << (source_bps - 1));
-		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
-
-		for(channel = 0; channel < channels; channel++) {
-			
-			samples = wide_samples;
-			data = start + bytes_per_sample * channel;
-			input_ = input[channel];
-
-			while(samples--) {
-				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
-
-				switch(target_bps) {
-					case 8:
-						data[0] = sample ^ 0x80;
-						break;
-					case 16:
-						data[0] = (FLAC__byte)(sample >> 8);
-						data[1] = (FLAC__byte)sample;
-						break;
-					case 24:
-						data[0] = (FLAC__byte)(sample >> 16);
-						data[1] = (FLAC__byte)(sample >> 8);
-						data[2] = (FLAC__byte)sample;
-						break;
-				}
-
-				data += incr;
-			}
-		}
-	}
-	else {
-		for(channel = 0; channel < channels; channel++) {
-			samples = wide_samples;
-			data = start + bytes_per_sample * channel;
-			input_ = input[channel];
-
-			while(samples--) {
-				sample = *input_++;
-
-				switch(target_bps) {
-					case 8:
-						data[0] = sample ^ 0x80;
-						break;
-					case 16:
-						data[0] = (FLAC__byte)(sample >> 8);
-						data[1] = (FLAC__byte)sample;
-						break;
-					case 24:
-						data[0] = (FLAC__byte)(sample >> 16);
-						data[1] = (FLAC__byte)(sample >> 8);
-						data[2] = (FLAC__byte)sample;
-						break;
-				}
-
-				data += incr;
-			}
-		}
-	}
-
-	return wide_samples * channels * (target_bps/8);
-}
-
-size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
-{
-	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
-	FLAC__byte * const start = data;
-	FLAC__int32 sample;
-	const FLAC__int32 *input_;
-	unsigned samples, channel;
-	const unsigned bytes_per_sample = target_bps / 8;
-	const unsigned incr = bytes_per_sample * channels;
-
-	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
-	FLAC__ASSERT(source_bps < 32);
-	FLAC__ASSERT(target_bps <= 24);
-	FLAC__ASSERT(target_bps <= source_bps);
-	FLAC__ASSERT((source_bps & 7) == 0);
-	FLAC__ASSERT((target_bps & 7) == 0);
-
-	if(source_bps != target_bps) {
-		const FLAC__int32 MIN = -(1L << (source_bps - 1));
-		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
-
-		for(channel = 0; channel < channels; channel++) {
-			
-			samples = wide_samples;
-			data = start + bytes_per_sample * channel;
-			input_ = input[channel];
-
-			while(samples--) {
-				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
-
-				switch(target_bps) {
-					case 8:
-						data[0] = sample ^ 0x80;
-						break;
-					case 24:
-						data[2] = (FLAC__byte)(sample >> 16);
-						/* fall through */
-					case 16:
-						data[1] = (FLAC__byte)(sample >> 8);
-						data[0] = (FLAC__byte)sample;
-				}
-
-				data += incr;
-			}
-		}
-	}
-	else {
-		for(channel = 0; channel < channels; channel++) {
-			samples = wide_samples;
-			data = start + bytes_per_sample * channel;
-			input_ = input[channel];
-
-			while(samples--) {
-				sample = *input_++;
-
-				switch(target_bps) {
-					case 8:
-						data[0] = sample ^ 0x80;
-						break;
-					case 24:
-						data[2] = (FLAC__byte)(sample >> 16);
-						/* fall through */
-					case 16:
-						data[1] = (FLAC__byte)(sample >> 8);
-						data[0] = (FLAC__byte)sample;
-				}
-
-				data += incr;
-			}
-		}
-	}
-
-	return wide_samples * channels * (target_bps/8);
-}
--- a/src/flac/plugin_common/dither.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__PLUGIN_COMMON__DITHER_H
-#define FLAC__PLUGIN_COMMON__DITHER_H
-
-#include <stdlib.h> /* for size_t */
-#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */
-#include "FLAC/ordinals.h"
-
-size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
-size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
-
-#endif
--- a/src/flac/plugin_common/locale_hack.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * Based on:
- * locale.h - 2000/05/05 13:10 Jerome Couderc
- *  EasyTAG - Tag editor for MP3 and OGG files
- *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-/*
- * Gettext support for EasyTAG
- */
-
-
-#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H
-#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H
-
-#include <locale.h>
-
-/*
- * Standard gettext macros.
- */
-#ifdef ENABLE_NLS
-#  include <libintl.h>
-#  define _(String) gettext (String)
-#  ifdef gettext_noop
-#    define N_(String) gettext_noop (String)
-#  else
-#    define N_(String) (String)
-#  endif
-#else
-#  define textdomain(String) (String)
-#  define gettext(String) (String)
-#  define dgettext(Domain,Message) (Message)
-#  define dcgettext(Domain,Message,Type) (Message)
-#  define bindtextdomain(Domain,Directory) (Domain)
-#  define _(String) (String)
-#  define N_(String) (String)
-#endif
-
-
-#endif
--- a/src/flac/plugin_common/replaygain.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
- * Copyright (C) 2003  Philip Jägenstedt
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#if HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "replaygain.h"
-#include "FLAC/ordinals.h"
-#include "FLAC/metadata.h"
-#include "grabbag.h"
-
-void FLAC_plugin__replaygain_get_from_file(const char *filename,
-                                           double *reference, FLAC__bool *reference_set,
-                                           double *track_gain, FLAC__bool *track_gain_set,
-                                           double *album_gain, FLAC__bool *album_gain_set,
-                                           double *track_peak, FLAC__bool *track_peak_set,
-                                           double *album_peak, FLAC__bool *album_peak_set)
-{
-	FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
-
-	*track_gain_set = *album_gain_set = *track_peak_set = *album_peak_set = false;
-
-	if(0 != iterator) {
-		if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
-			FLAC__bool got_vorbis_comments = false;
-			do {
-				if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
-					FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
-					if(0 != block) {
-						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/false, /*strict=*/true, reference, track_gain, track_peak)) {
-							*reference_set = *track_gain_set = *track_peak_set = true;
-						}
-						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/true, /*strict=*/true, reference, album_gain, album_peak)) {
-							*reference_set = *album_gain_set = *album_peak_set = true;
-						}
-						FLAC__metadata_object_delete(block);
-						got_vorbis_comments = true;
-					}
-				}
-			} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
-		}
-		FLAC__metadata_simple_iterator_delete(iterator);
-	}
-	return;
-}
--- a/src/flac/plugin_common/replaygain.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
- * Copyright (C) 2003  Philip Jägenstedt
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#ifndef FLAC__PLUGIN_COMMON__REPLAYGAIN_H
-#define FLAC__PLUGIN_COMMON__REPLAYGAIN_H
-
-#include "FLAC/ordinals.h"
-
-void FLAC_plugin__replaygain_get_from_file(const char *filename,
-                                           double *reference, FLAC__bool *reference_set,
-                                           double *track_gain, FLAC__bool *track_gain_set,
-                                           double *album_gain, FLAC__bool *album_gain_set,
-                                           double *track_peak, FLAC__bool *track_peak_set,
-                                           double *album_peak, FLAC__bool *album_peak_set);
-
-#endif
--- a/src/flac/plugin_common/tags.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "tags.h"
-#include "FLAC/assert.h"
-#include "FLAC/metadata.h"
-
-
-static __inline unsigned local__wide_strlen(const FLAC__uint16 *s)
-{
-	unsigned n = 0;
-	while(*s++)
-		n++;
-	return n;
-}
-
-static __inline unsigned local__utf8len(const FLAC__byte *utf8)
-{
-	FLAC__ASSERT(0 != utf8);
-	if ((utf8[0] & 0x80) == 0)
-		return 1;
-	else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80)
-		return 2;
-	else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80)
-		return 3;
-	else
-		return 0;
-}
-
-static __inline unsigned local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2)
-{
-	const unsigned len = local__utf8len(utf8);
-
-	FLAC__ASSERT(0 != ucs2);
-
-	if (len == 1)
-		*ucs2 = *utf8;
-	else if (len == 2)
-		*ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
-	else if (len == 3)
-		*ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
-
-	return len;
-}
-
-static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, unsigned length)
-{
-	FLAC__uint16 *out;
-	unsigned chars = 0;
-
-	FLAC__ASSERT(0 != src);
-
-	/* calculate length */
-	{
-		const char *s, *end;
-		for (s=src, end=src+length; s<end; chars++) {
-			const unsigned n = local__utf8len((unsigned char*)s);
-			if (n == 0)
-				return 0;
-			s += n;
-		}
-		FLAC__ASSERT(s == end);
-	}
-
-	/* allocate */
-	out = (FLAC__uint16*)malloc(chars * sizeof(FLAC__uint16));
-	if (0 == out) {
-		FLAC__ASSERT(0);
-		return 0;
-	}
-
-	/* convert */
-	{
-		FLAC__uint16 *u = out;
-		for ( ; chars; chars--)
-			src += local__utf8_to_ucs2((const unsigned char*)src, u++);
-	}
-
-	return out;
-}
-
-static __inline unsigned local__ucs2len(FLAC__uint16 ucs2)
-{
-	if (ucs2 < 0x0080)
-		return 1;
-	else if (ucs2 < 0x0800)
-		return 2;
-	else
-		return 3;
-}
-
-static __inline unsigned local__ucs2_to_utf8(FLAC__uint16 ucs2, FLAC__byte *utf8)
-{
-	if (ucs2 < 0x080) {
-		utf8[0] = (FLAC__byte)ucs2;
-		return 1;
-	}
-	else if (ucs2 < 0x800) {
-		utf8[0] = 0xc0 | (ucs2 >> 6);
-		utf8[1] = 0x80 | (ucs2 & 0x3f);
-		return 2;
-	}
-	else {
-		utf8[0] = 0xe0 | (ucs2 >> 12);
-		utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
-		utf8[2] = 0x80 | (ucs2 & 0x3f);
-		return 3;
-	}
-}
-
-static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, unsigned length)
-{
-	char *out;
-	unsigned len = 0;
-
-	FLAC__ASSERT(0 != src);
-
-	/* calculate length */
-	{
-		unsigned i;
-		for (i = 0; i < length; i++)
-			len += local__ucs2len(src[i]);
-	}
-
-	/* allocate */
-	out = (char*)malloc(len * sizeof(char));
-	if (0 == out)
-		return 0;
-
-	/* convert */
-	{
-		unsigned char *u = (unsigned char*) out;
-		for ( ; *src; src++)
-			u += local__ucs2_to_utf8(*src, u);
-		local__ucs2_to_utf8(*src, u);
-	}
-
-	return out;
-}
-
-
-FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags)
-{
-	if(!FLAC__metadata_get_tags(filename, tags))
-		if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
-			return false;
-	return true;
-}
-
-FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags)
-{
-	FLAC__Metadata_Chain *chain;
-	FLAC__Metadata_Iterator *iterator;
-	FLAC__StreamMetadata *block;
-	FLAC__bool got_vorbis_comments = false;
-	FLAC__bool ok;
-
-	if(0 == (chain = FLAC__metadata_chain_new()))
-		return false;
-
-	if(!FLAC__metadata_chain_read(chain, filename)) {
-		FLAC__metadata_chain_delete(chain);
-		return false;
-	}
-
-	if(0 == (iterator = FLAC__metadata_iterator_new())) {
-		FLAC__metadata_chain_delete(chain);
-		return false;
-	}
-
-	FLAC__metadata_iterator_init(iterator, chain);
-
-	do {
-		if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
-			got_vorbis_comments = true;
-	} while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator));
-
-	if(0 == (block = FLAC__metadata_object_clone(tags))) {
-		FLAC__metadata_chain_delete(chain);
-		FLAC__metadata_iterator_delete(iterator);
-		return false;
-	}
-
-	if(got_vorbis_comments)
-		ok = FLAC__metadata_iterator_set_block(iterator, block);
-	else
-		ok = FLAC__metadata_iterator_insert_block_after(iterator, block);
-
-	FLAC__metadata_iterator_delete(iterator);
-
-	if(ok) {
-		FLAC__metadata_chain_sort_padding(chain);
-		ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true);
-	}
-
-	FLAC__metadata_chain_delete(chain);
-
-	return ok;
-}
-
-void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags)
-{
-	FLAC__metadata_object_delete(*tags);
-	*tags = 0;
-}
-
-const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name)
-{
-	const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name);
-	return (i < 0? 0 : strchr((const char*)tags->data.vorbis_comment.comments[i].entry, '=')+1);
-}
-
-FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name)
-{
-	const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
-	if(0 == utf8)
-		return 0;
-	return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */
-}
-
-int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name)
-{
-	return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name);
-}
-
-int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags)
-{
-	int n = (int)tags->data.vorbis_comment.num_comments;
-	if(n > 0) {
-		if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0))
-			n = -1;
-	}
-	return n;
-}
-
-FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator)
-{
-	int i;
-
-	FLAC__ASSERT(0 != tags);
-	FLAC__ASSERT(0 != name);
-	FLAC__ASSERT(0 != value);
-
-	if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) {
-		FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i;
-		const size_t value_len = strlen(value);
-		const size_t separator_len = strlen(separator);
-		FLAC__byte *new_entry;
-		if(0 == (new_entry = (FLAC__byte*)realloc(entry->entry, entry->length + value_len + separator_len + 1)))
-			return false;
-		memcpy(new_entry+entry->length, separator, separator_len);
-		entry->length += separator_len;
-		memcpy(new_entry+entry->length, value, value_len);
-		entry->length += value_len;
-		new_entry[entry->length] = '\0';
-		entry->entry = new_entry;
-	}
-	else {
-		FLAC__StreamMetadata_VorbisComment_Entry entry;
-		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value))
-			return false;
-		FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false);
-	}
-	return true;
-}
-
-FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all)
-{
-	FLAC__StreamMetadata_VorbisComment_Entry entry;
-
-	FLAC__ASSERT(0 != tags);
-	FLAC__ASSERT(0 != name);
-	FLAC__ASSERT(0 != value);
-
-	{
-		char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */
-		if(0 == utf8)
-			return false;
-		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) {
-			free(utf8);
-			return false;
-		}
-		free(utf8);
-	}
-	if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false))
-		return false;
-	return true;
-}
--- a/src/flac/plugin_common/tags.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/* plugin_common - Routines common to several plugins
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__PLUGIN_COMMON__TAGS_H
-#define FLAC__PLUGIN_COMMON__TAGS_H
-
-#include "FLAC/format.h"
-
-FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags);
-FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags);
-
-/*
- * Deletes the tags object and sets '*tags' to NULL.
- */
-void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags);
-
-/*
- * Gets the value (in UTF-8) of the first tag with the given name (NULL if no
- * such tag exists).
- */
-const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name);
-
-/*
- * Gets the value (in UCS-2) of the first tag with the given name (NULL if no
- * such tag exists).
- *
- * NOTE: the returned string is malloc()ed and must be free()d by the caller.
- */
-FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name);
-
-/*
- * Removes all tags with the given 'name'.  Returns the number of tags removed,
- * or -1 on memory allocation error.
- */
-int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name);
-
-/*
- * Removes all tags.  Returns the number of tags removed, or -1 on memory
- * allocation error.
- */
-int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags);
-
-/*
- * Adds a "name=value" tag to the tags.  'value' must be in UTF-8.  If
- * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the
- * first such tag's value is appended with separator, then value.
- */
-FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator);
-
-/*
- * Adds a "name=value" tag to the tags.  'value' must be in UCS-2.  If 'tags'
- * already contains a tag or tags for 'name', then they will be replaced
- * according to 'replace_all': if 'replace_all' is false, only the first such
- * tag will be replaced; if true, all matching tags will be replaced by the one
- * new tag. 
- */
-FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all);
-
-#endif
--- a/src/flac/replaygain.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,665 +0,0 @@
-/* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#if HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "grabbag.h"
-#include "replaygain_analysis.h"
-#include "FLAC/assert.h"
-#include "FLAC/metadata.h"
-#include "FLAC/stream_decoder.h"
-#include <locale.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined _MSC_VER || defined __MINGW32__
-#include <io.h> /* for chmod() */
-#endif
-#include <sys/stat.h> /* for stat(), maybe chmod() */
-
-#ifdef local_min
-#undef local_min
-#endif
-#define local_min(a,b) ((a)<(b)?(a):(b))
-
-#ifdef local_max
-#undef local_max
-#endif
-#define local_max(a,b) ((a)>(b)?(a):(b))
-
-static const char *reference_format_ = "%s=%2.1f dB";
-static const char *gain_format_ = "%s=%+2.2f dB";
-static const char *peak_format_ = "%s=%1.8f";
-
-static double album_peak_, title_peak_;
-
-const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
-/*
-	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
-	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
-	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
-	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
-	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
-*/
-
-const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
-const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
-const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
-const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
-const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
-
-
-static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != stats);
-	return (0 == stat(filename, stats));
-}
-
-static void set_file_stats_(const char *filename, struct stat *stats)
-{
-	FLAC__ASSERT(0 != filename);
-	FLAC__ASSERT(0 != stats);
-
-	(void)chmod(filename, stats->st_mode);
-}
-
-static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value)
-{
-	char buffer[256];
-	char *saved_locale;
-	FLAC__StreamMetadata_VorbisComment_Entry entry;
-
-	FLAC__ASSERT(0 != block);
-	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-	FLAC__ASSERT(0 != format);
-	FLAC__ASSERT(0 != name);
-
-	buffer[sizeof(buffer)-1] = '\0';
-	/*
-	 * We need to save the old locale and switch to "C" because the locale
-	 * influences the formatting of %f and we want it a certain way.
-	 */
-	saved_locale = setlocale(LC_ALL, 0);
-	setlocale(LC_ALL, "C");
-#if defined _MSC_VER || defined __MINGW32__
-	_snprintf(buffer, sizeof(buffer)-1, format, name, value);
-#else
-	snprintf(buffer, sizeof(buffer)-1, format, name, value);
-#endif
-	setlocale(LC_ALL, saved_locale);
-
-	entry.entry = (FLAC__byte *)buffer;
-	entry.length = strlen(buffer);
-
-	return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
-}
-
-FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency)
-{
-	static const unsigned valid_sample_rates[] = {
-		8000,
-		11025,
-		12000,
-		16000,
-		22050,
-		24000,
-		32000,
-		44100,
-		48000
-	};
-	static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]);
-
-	unsigned i;
-
-	for(i = 0; i < n_valid_sample_rates; i++)
-		if(sample_frequency == valid_sample_rates[i])
-			return true;
-	return false;
-}
-
-FLAC__bool grabbag__replaygain_init(unsigned sample_frequency)
-{
-	title_peak_ = album_peak_ = 0.0;
-	return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK;
-}
-
-FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples)
-{
-	/* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
-	static Float_t lbuffer[2048], rbuffer[2048];
-	static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
-	FLAC__int32 block_peak = 0, s;
-	unsigned i, j;
-
-	FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE);
-	FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4);
-	/*
-	 * We use abs() on a FLAC__int32 which is undefined for the most negative value.
-	 * If the reference codec ever handles 32bps we will have to write a special
-	 * case here.
-	 */
-	FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32);
-
-	if(bps == 16) {
-		if(is_stereo) {
-			j = 0;
-			while(samples > 0) {
-				const unsigned n = local_min(samples, nbuffer);
-				for(i = 0; i < n; i++, j++) {
-					s = input[0][j];
-					lbuffer[i] = (Float_t)s;
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-
-					s = input[1][j];
-					rbuffer[i] = (Float_t)s;
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-				}
-				samples -= n;
-				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
-					return false;
-			}
-		}
-		else {
-			j = 0;
-			while(samples > 0) {
-				const unsigned n = local_min(samples, nbuffer);
-				for(i = 0; i < n; i++, j++) {
-					s = input[0][j];
-					lbuffer[i] = (Float_t)s;
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-				}
-				samples -= n;
-				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
-					return false;
-			}
-		}
-	}
-	else { /* bps must be < 32 according to above assertion */
-		const double scale = (
-			(bps > 16)?
-				(double)1. / (double)(1u << (bps - 16)) :
-				(double)(1u << (16 - bps))
-		);
-
-		if(is_stereo) {
-			j = 0;
-			while(samples > 0) {
-				const unsigned n = local_min(samples, nbuffer);
-				for(i = 0; i < n; i++, j++) {
-					s = input[0][j];
-					lbuffer[i] = (Float_t)(scale * (double)s);
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-
-					s = input[1][j];
-					rbuffer[i] = (Float_t)(scale * (double)s);
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-				}
-				samples -= n;
-				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
-					return false;
-			}
-		}
-		else {
-			j = 0;
-			while(samples > 0) {
-				const unsigned n = local_min(samples, nbuffer);
-				for(i = 0; i < n; i++, j++) {
-					s = input[0][j];
-					lbuffer[i] = (Float_t)(scale * (double)s);
-					s = abs(s);
-					block_peak = local_max(block_peak, s);
-				}
-				samples -= n;
-				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
-					return false;
-			}
-		}
-	}
-
-	{
-		const double peak_scale = (double)(1u << (bps - 1));
-		double peak = (double)block_peak / peak_scale;
-		if(peak > title_peak_)
-			title_peak_ = peak;
-		if(peak > album_peak_)
-			album_peak_ = peak;
-	}
-
-	return true;
-}
-
-void grabbag__replaygain_get_album(float *gain, float *peak)
-{
-	*gain = (float)GetAlbumGain();
-	*peak = (float)album_peak_;
-	album_peak_ = 0.0;
-}
-
-void grabbag__replaygain_get_title(float *gain, float *peak)
-{
-	*gain = (float)GetTitleGain();
-	*peak = (float)title_peak_;
-	title_peak_ = 0.0;
-}
-
-
-typedef struct {
-	unsigned channels;
-	unsigned bits_per_sample;
-	unsigned sample_rate;
-	FLAC__bool error;
-} DecoderInstance;
-
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
-{
-	DecoderInstance *instance = (DecoderInstance*)client_data;
-	const unsigned bits_per_sample = frame->header.bits_per_sample;
-	const unsigned channels = frame->header.channels;
-	const unsigned sample_rate = frame->header.sample_rate;
-	const unsigned samples = frame->header.blocksize;
-
-	(void)decoder;
-
-	if(
-		!instance->error &&
-		(channels == 2 || channels == 1) &&
-		bits_per_sample == instance->bits_per_sample &&
-		channels == instance->channels &&
-		sample_rate == instance->sample_rate
-	) {
-		instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples);
-	}
-	else {
-		instance->error = true;
-	}
-
-	if(!instance->error)
-		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-	else
-		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-}
-
-static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
-{
-	DecoderInstance *instance = (DecoderInstance*)client_data;
-
-	(void)decoder;
-
-	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
-		instance->bits_per_sample = metadata->data.stream_info.bits_per_sample;
-		instance->channels = metadata->data.stream_info.channels;
-		instance->sample_rate = metadata->data.stream_info.sample_rate;
-
-		if(instance->channels != 1 && instance->channels != 2) {
-			instance->error = true;
-			return;
-		}
-
-		if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) {
-			instance->error = true;
-			return;
-		}
-	}
-}
-
-static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
-{
-	DecoderInstance *instance = (DecoderInstance*)client_data;
-
-	(void)decoder, (void)status;
-
-	instance->error = true;
-}
-
-const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
-{
-	DecoderInstance instance;
-	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
-
-	if(0 == decoder)
-		return "memory allocation error";
-
-	instance.error = false;
-
-	/* It does these three by default but lets be explicit: */
-	FLAC__stream_decoder_set_md5_checking(decoder, false);
-	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
-	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
-
-	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
-		FLAC__stream_decoder_delete(decoder);
-		return "initializing decoder";
-	}
-
-	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
-		FLAC__stream_decoder_delete(decoder);
-		return "decoding file";
-	}
-
-	FLAC__stream_decoder_delete(decoder);
-
-	grabbag__replaygain_get_title(title_gain, title_peak);
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak)
-{
-	const char *error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak)))
-		return error;
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
-{
-	FLAC__ASSERT(0 != block);
-	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
-		return "memory allocation error";
-
-	if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
-		return "memory allocation error";
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
-{
-	FLAC__ASSERT(0 != block);
-	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	if(
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
-	)
-		return "memory allocation error";
-
-	if(
-		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
-		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
-	)
-		return "memory allocation error";
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak)
-{
-	FLAC__ASSERT(0 != block);
-	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	if(
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
-	)
-		return "memory allocation error";
-
-	if(
-		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
-		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
-	)
-		return "memory allocation error";
-
-	return 0;
-}
-
-static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block)
-{
-	FLAC__Metadata_Iterator *iterator;
-	const char *error;
-	FLAC__bool found_vc_block = false;
-
-	if(0 == (*chain = FLAC__metadata_chain_new()))
-		return "memory allocation error";
-
-	if(!FLAC__metadata_chain_read(*chain, filename)) {
-		error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
-		FLAC__metadata_chain_delete(*chain);
-		return error;
-	}
-
-	if(0 == (iterator = FLAC__metadata_iterator_new())) {
-		FLAC__metadata_chain_delete(*chain);
-		return "memory allocation error";
-	}
-
-	FLAC__metadata_iterator_init(iterator, *chain);
-
-	do {
-		*block = FLAC__metadata_iterator_get_block(iterator);
-		if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
-			found_vc_block = true;
-	} while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
-
-	if(!found_vc_block) {
-		/* create a new block */
-		*block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
-		if(0 == *block) {
-			FLAC__metadata_chain_delete(*chain);
-			FLAC__metadata_iterator_delete(iterator);
-			return "memory allocation error";
-		}
-		while(FLAC__metadata_iterator_next(iterator))
-			;
-		if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) {
-			error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
-			FLAC__metadata_chain_delete(*chain);
-			FLAC__metadata_iterator_delete(iterator);
-			return error;
-		}
-		/* iterator is left pointing to new block */
-		FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block);
-	}
-
-	FLAC__metadata_iterator_delete(iterator);
-
-	FLAC__ASSERT(0 != *block);
-	FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	return 0;
-}
-
-static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime)
-{
-	struct stat stats;
-	const FLAC__bool have_stats = get_file_stats_(filename, &stats);
-
-	(void)grabbag__file_change_stats(filename, /*read_only=*/false);
-
-	FLAC__metadata_chain_sort_padding(chain);
-	if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) {
-		FLAC__metadata_chain_delete(chain);
-		return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
-	}
-
-	FLAC__metadata_chain_delete(chain);
-
-	if(have_stats)
-		set_file_stats_(filename, &stats);
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime)
-{
-	FLAC__Metadata_Chain *chain;
-	FLAC__StreamMetadata *block;
-	const char *error;
-
-	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) {
-		FLAC__metadata_chain_delete(chain);
-		return error;
-	}
-
-	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
-		return error;
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
-{
-	FLAC__Metadata_Chain *chain;
-	FLAC__StreamMetadata *block;
-	const char *error;
-
-	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
-		FLAC__metadata_chain_delete(chain);
-		return error;
-	}
-
-	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
-		return error;
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
-{
-	FLAC__Metadata_Chain *chain;
-	FLAC__StreamMetadata *block;
-	const char *error;
-
-	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) {
-		FLAC__metadata_chain_delete(chain);
-		return error;
-	}
-
-	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
-		return error;
-
-	return 0;
-}
-
-const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime)
-{
-	FLAC__Metadata_Chain *chain;
-	FLAC__StreamMetadata *block;
-	const char *error;
-
-	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
-		return error;
-
-	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) {
-		FLAC__metadata_chain_delete(chain);
-		return error;
-	}
-
-	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
-		return error;
-
-	return 0;
-}
-
-static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val)
-{
-	char s[32], *end;
-	const char *p, *q;
-	double v;
-
-	FLAC__ASSERT(0 != entry);
-	FLAC__ASSERT(0 != val);
-
-	p = (const char *)entry->entry;
-	q = strchr(p, '=');
-	if(0 == q)
-		return false;
-	q++;
-	memset(s, 0, sizeof(s)-1);
-	strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p)));
-
-	v = strtod(s, &end);
-	if(end == s)
-		return false;
-
-	*val = v;
-	return true;
-}
-
-FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
-{
-	int reference_offset, gain_offset, peak_offset;
-
-	FLAC__ASSERT(0 != block);
-	FLAC__ASSERT(0 != reference);
-	FLAC__ASSERT(0 != gain);
-	FLAC__ASSERT(0 != peak);
-	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
-	/* Default to current level until overridden by a detected tag; this
-	 * will always be true until we change replaygain_analysis.c
-	 */
-	*reference = ReplayGainReferenceLoudness;
-
-	if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
-		(void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
-
-	if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
-		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
-	if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
-		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
-
-	if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
-		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
-	if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
-		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
-
-	return true;
-}
-
-double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping)
-{
-	double scale;
-	FLAC__ASSERT(peak >= 0.0);
- 	gain += preamp;
-	scale = (float) pow(10.0, gain * 0.05);
-	if(prevent_clipping && peak > 0.0) {
-		const double max_scale = (float)(1.0 / peak);
-		if(scale > max_scale)
-			scale = max_scale;
-	}
-	return scale;
-}
--- a/src/flac/replaygain_analysis.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,419 +0,0 @@
-/*
- *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
- *  Copyright (C) 2001 David Robinson and Glen Sawyer
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- *  concept and filter values by David Robinson (David@Robinson.org)
- *    -- blame him if you think the idea is flawed
- *  original coding by Glen Sawyer (glensawyer@hotmail.com)
- *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
- *
- *  lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
- *    -- credit him for all the _good_ programming ;)
- *
- *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
- *
- *
- *  For an explanation of the concepts and the basic algorithms involved, go to:
- *    http://www.replaygain.org/
- */
-
-/*
- *  Here's the deal. Call
- *
- *    InitGainAnalysis ( long samplefreq );
- *
- *  to initialize everything. Call
- *
- *    AnalyzeSamples ( const Float_t*  left_samples,
- *                     const Float_t*  right_samples,
- *                     size_t          num_samples,
- *                     int             num_channels );
- *
- *  as many times as you want, with as many or as few samples as you want.
- *  If mono, pass the sample buffer in through left_samples, leave
- *  right_samples NULL, and make sure num_channels = 1.
- *
- *    GetTitleGain()
- *
- *  will return the recommended dB level change for all samples analyzed
- *  SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
- *
- *    GetAlbumGain()
- *
- *  will return the recommended dB level change for all samples analyzed
- *  since InitGainAnalysis() was called and finalized with GetTitleGain().
- *
- *  Pseudo-code to process an album:
- *
- *    Float_t       l_samples [4096];
- *    Float_t       r_samples [4096];
- *    size_t        num_samples;
- *    unsigned int  num_songs;
- *    unsigned int  i;
- *
- *    InitGainAnalysis ( 44100 );
- *    for ( i = 1; i <= num_songs; i++ ) {
- *        while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
- *            AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
- *        fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
- *    }
- *    fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
- */
-
-/*
- *  So here's the main source of potential code confusion:
- *
- *  The filters applied to the incoming samples are IIR filters,
- *  meaning they rely on up to <filter order> number of previous samples
- *  AND up to <filter order> number of previous filtered samples.
- *
- *  I set up the AnalyzeSamples routine to minimize memory usage and interface
- *  complexity. The speed isn't compromised too much (I don't think), but the
- *  internal complexity is higher than it should be for such a relatively
- *  simple routine.
- *
- *  Optimization/clarity suggestions are welcome.
- */
-
-#if HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "replaygain_analysis.h"
-
-Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
-
-typedef unsigned short  Uint16_t;
-typedef signed short    Int16_t;
-typedef unsigned int    Uint32_t;
-typedef signed int      Int32_t;
-
-#define YULE_ORDER         10
-#define BUTTER_ORDER        2
-#define RMS_PERCENTILE      0.95        /* percentile which is louder than the proposed level */
-#define MAX_SAMP_FREQ   48000.          /* maximum allowed sample frequency [Hz] */
-#define RMS_WINDOW_TIME     0.050       /* Time slice size [s] */
-#define STEPS_per_dB      100.          /* Table entries per dB */
-#define MAX_dB            120.          /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
-
-#define MAX_ORDER               (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
-/* [JEC] the following was originally #defined as:
- *   (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME)
- * but that seemed to fail to take into account the ceil() part of the
- * sampleWindow calculation in ResetSampleFrequency(), and was causing
- * buffer overflows for 48kHz analysis, hence the +1.
- */
-#define MAX_SAMPLES_PER_WINDOW  (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.)   /* max. Samples per Time slice */
-#define PINK_REF                64.82 /* 298640883795 */                          /* calibration value */
-
-static Float_t          linprebuf [MAX_ORDER * 2];
-static Float_t*         linpre;                                          /* left input samples, with pre-buffer */
-static Float_t          lstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
-static Float_t*         lstep;                                           /* left "first step" (i.e. post first filter) samples */
-static Float_t          loutbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
-static Float_t*         lout;                                            /* left "out" (i.e. post second filter) samples */
-static Float_t          rinprebuf [MAX_ORDER * 2];
-static Float_t*         rinpre;                                          /* right input samples ... */
-static Float_t          rstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
-static Float_t*         rstep;
-static Float_t          routbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
-static Float_t*         rout;
-static unsigned int              sampleWindow;                           /* number of samples required to reach number of milliseconds required for RMS window */
-static unsigned long    totsamp;
-static double           lsum;
-static double           rsum;
-static int              freqindex;
-static Uint32_t  A [(size_t)(STEPS_per_dB * MAX_dB)];
-static Uint32_t  B [(size_t)(STEPS_per_dB * MAX_dB)];
-
-/* for each filter:
-   [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */
-
-#ifdef WIN32
-#pragma warning ( disable : 4305 )
-#endif
-
-static const Float_t  AYule [9] [11] = {
-    { 1., -3.84664617118067,  7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294,  9.48293806319790, -5.87257861775999,  2.75465861874613, -0.86984376593551, 0.13919314567432 },
-    { 1., -3.47845948550071,  6.36317777566148, -8.54751527471874,  9.47693607801280, -8.81498681370155,  6.85401540936998, -4.39470996079559,  2.19611684890774, -0.75104302451432, 0.13149317958808 },
-    { 1., -2.37898834973084,  2.84868151156327, -2.64577170229825,  2.23697657451713, -1.67148153367602,  1.00595954808547, -0.45953458054983,  0.16378164858596, -0.05032077717131, 0.02347897407020 },
-    { 1., -1.61273165137247,  1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906,  0.39120800788284, -0.22138138954925,  0.04500235387352,  0.02005851806501, 0.00302439095741 },
-    { 1., -1.49858979367799,  0.87350271418188,  0.12205022308084, -0.80774944671438,  0.47854794562326, -0.12453458140019, -0.04067510197014,  0.08333755284107, -0.04237348025746, 0.02977207319925 },
-    { 1., -0.62820619233671,  0.29661783706366, -0.37256372942400,  0.00213767857124, -0.42029820170918,  0.22199650564824,  0.00613424350682,  0.06747620744683,  0.05784820375801, 0.03222754072173 },
-    { 1., -1.04800335126349,  0.29156311971249, -0.26806001042947,  0.00819999645858,  0.45054734505008, -0.33032403314006,  0.06739368333110, -0.04784254229033,  0.01639907836189, 0.01807364323573 },
-    { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477,  0.14728154134330,  0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053,  0.02442357316099, 0.01818801111503 },
-    { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242,  0.26408300200955,  0.15113130533216, -0.17556493366449, -0.18823009262115,  0.05477720428674, 0.04704409688120 }
-};
-
-static const Float_t  BYule [9] [11] = {
-    { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619,  0.02161526843274, -0.02074045215285,  0.00594298065125,  0.00306428023191,  0.00012025322027,  0.00288463683916 },
-    { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936,  0.02245293253339, -0.02596338512915,  0.01624864962975, -0.00240879051584,  0.00674613682247, -0.00187763777362 },
-    { 0.15457299681924, -0.09331049056315, -0.06247880153653,  0.02163541888798, -0.05588393329856,  0.04781476674921,  0.00222312597743,  0.03174092540049, -0.01390589421898,  0.00651420667831, -0.00881362733839 },
-    { 0.30296907319327, -0.22613988682123, -0.08587323730772,  0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913,  0.06276101321749, -0.00000828086748,  0.00205861885564, -0.02950134983287 },
-    { 0.33642304856132, -0.25572241425570, -0.11828570177555,  0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440,  0.05724228140351,  0.00832043980773, -0.01635381384540, -0.01760176568150 },
-    { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551,  0.04078262797139, -0.12398163381748,  0.04097565135648,  0.10478503600251, -0.01863887810927, -0.03193428438915,  0.00541907748707 },
-    { 0.56619470757641, -0.75464456939302,  0.16242137742230,  0.16744243493672, -0.18901604199609,  0.30931782841830, -0.27562961986224,  0.00647310677246,  0.08647503780351, -0.03788984554840, -0.00588215443421 },
-    { 0.58100494960553, -0.53174909058578, -0.14289799034253,  0.17520704835522,  0.02377945217615,  0.15558449135573, -0.25344790059353,  0.01628462406333,  0.06920467763959, -0.03721611395801, -0.00749618797172 },
-    { 0.53648789255105, -0.42163034350696, -0.00275953611929,  0.04267842219415, -0.10214864179676,  0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000,  0.04788665548180, -0.02217936801134 }
-};
-
-static const Float_t  AButter [9] [3] = {
-    { 1., -1.97223372919527, 0.97261396931306 },
-    { 1., -1.96977855582618, 0.97022847566350 },
-    { 1., -1.95835380975398, 0.95920349965459 },
-    { 1., -1.95002759149878, 0.95124613669835 },
-    { 1., -1.94561023566527, 0.94705070426118 },
-    { 1., -1.92783286977036, 0.93034775234268 },
-    { 1., -1.91858953033784, 0.92177618768381 },
-    { 1., -1.91542108074780, 0.91885558323625 },
-    { 1., -1.88903307939452, 0.89487434461664 }
-};
-
-static const Float_t  BButter [9] [3] = {
-    { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
-    { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
-    { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
-    { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
-    { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
-    { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
-    { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
-    { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
-    { 0.94597685600279, -1.89195371200558, 0.94597685600279 }
-};
-
-#ifdef WIN32
-#pragma warning ( default : 4305 )
-#endif
-
-/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
-
-static void
-filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order )
-{
-    double  y;
-    size_t  i;
-    size_t  k;
-
-    for ( i = 0; i < nSamples; i++ ) {
-        y = input[i] * b[0];
-        for ( k = 1; k <= order; k++ )
-            y += input[i-k] * b[k] - output[i-k] * a[k];
-        output[i] = (Float_t)y;
-    }
-}
-
-/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
-
-int
-ResetSampleFrequency ( long samplefreq ) {
-    int  i;
-
-    /* zero out initial values */
-    for ( i = 0; i < MAX_ORDER; i++ )
-        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
-
-    switch ( (int)(samplefreq) ) {
-        case 48000: freqindex = 0; break;
-        case 44100: freqindex = 1; break;
-        case 32000: freqindex = 2; break;
-        case 24000: freqindex = 3; break;
-        case 22050: freqindex = 4; break;
-        case 16000: freqindex = 5; break;
-        case 12000: freqindex = 6; break;
-        case 11025: freqindex = 7; break;
-        case  8000: freqindex = 8; break;
-        default:    return INIT_GAIN_ANALYSIS_ERROR;
-    }
-
-    sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME);
-
-    lsum         = 0.;
-    rsum         = 0.;
-    totsamp      = 0;
-
-    memset ( A, 0, sizeof(A) );
-
-	return INIT_GAIN_ANALYSIS_OK;
-}
-
-int
-InitGainAnalysis ( long samplefreq )
-{
-	if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) {
-		return INIT_GAIN_ANALYSIS_ERROR;
-	}
-
-    linpre       = linprebuf + MAX_ORDER;
-    rinpre       = rinprebuf + MAX_ORDER;
-    lstep        = lstepbuf  + MAX_ORDER;
-    rstep        = rstepbuf  + MAX_ORDER;
-    lout         = loutbuf   + MAX_ORDER;
-    rout         = routbuf   + MAX_ORDER;
-
-    memset ( B, 0, sizeof(B) );
-
-    return INIT_GAIN_ANALYSIS_OK;
-}
-
-/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
-
-int
-AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels )
-{
-    const Float_t*  curleft;
-    const Float_t*  curright;
-    long            batchsamples;
-    long            cursamples;
-    long            cursamplepos;
-    int             i;
-
-    if ( num_samples == 0 )
-        return GAIN_ANALYSIS_OK;
-
-    cursamplepos = 0;
-    batchsamples = num_samples;
-
-    switch ( num_channels) {
-    case  1: right_samples = left_samples;
-    case  2: break;
-    default: return GAIN_ANALYSIS_ERROR;
-    }
-
-    if ( num_samples < MAX_ORDER ) {
-        memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) );
-        memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) );
-    }
-    else {
-        memcpy ( linprebuf + MAX_ORDER, left_samples,  MAX_ORDER   * sizeof(Float_t) );
-        memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER   * sizeof(Float_t) );
-    }
-
-    while ( batchsamples > 0 ) {
-        cursamples = batchsamples > (long)(sampleWindow-totsamp)  ?  (long)(sampleWindow - totsamp)  :  batchsamples;
-        if ( cursamplepos < MAX_ORDER ) {
-            curleft  = linpre+cursamplepos;
-            curright = rinpre+cursamplepos;
-            if (cursamples > MAX_ORDER - cursamplepos )
-                cursamples = MAX_ORDER - cursamplepos;
-        }
-        else {
-            curleft  = left_samples  + cursamplepos;
-            curright = right_samples + cursamplepos;
-        }
-
-        filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
-        filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
-
-        filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
-        filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
-
-        for ( i = 0; i < cursamples; i++ ) {             /* Get the squared values */
-            lsum += lout [totsamp+i] * lout [totsamp+i];
-            rsum += rout [totsamp+i] * rout [totsamp+i];
-        }
-
-        batchsamples -= cursamples;
-        cursamplepos += cursamples;
-        totsamp      += cursamples;
-        if ( totsamp == sampleWindow ) {  /* Get the Root Mean Square (RMS) for this set of samples */
-            double  val  = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 );
-            int     ival = (int) val;
-            if ( ival <                     0 ) ival = 0;
-            if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1;
-            A [ival]++;
-            lsum = rsum = 0.;
-            memmove ( loutbuf , loutbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
-            memmove ( routbuf , routbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
-            memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
-            memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
-            totsamp = 0;
-        }
-        if ( totsamp > sampleWindow )   /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
-            return GAIN_ANALYSIS_ERROR;
-    }
-    if ( num_samples < MAX_ORDER ) {
-        memmove ( linprebuf,                           linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
-        memmove ( rinprebuf,                           rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
-        memcpy  ( linprebuf + MAX_ORDER - num_samples, left_samples,          num_samples             * sizeof(Float_t) );
-        memcpy  ( rinprebuf + MAX_ORDER - num_samples, right_samples,         num_samples             * sizeof(Float_t) );
-    }
-    else {
-        memcpy  ( linprebuf, left_samples  + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
-        memcpy  ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
-    }
-
-    return GAIN_ANALYSIS_OK;
-}
-
-
-static Float_t
-analyzeResult ( Uint32_t* Array, size_t len )
-{
-    Uint32_t  elems;
-    Int32_t   upper;
-    size_t    i;
-
-    elems = 0;
-    for ( i = 0; i < len; i++ )
-        elems += Array[i];
-    if ( elems == 0 )
-        return GAIN_NOT_ENOUGH_SAMPLES;
-
-    upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE));
-    for ( i = len; i-- > 0; ) {
-        if ( (upper -= Array[i]) <= 0 )
-            break;
-    }
-
-    return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB);
-}
-
-
-Float_t
-GetTitleGain ( void )
-{
-    Float_t  retval;
-    unsigned int    i;
-
-    retval = analyzeResult ( A, sizeof(A)/sizeof(*A) );
-
-    for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) {
-        B[i] += A[i];
-        A[i]  = 0;
-    }
-
-    for ( i = 0; i < MAX_ORDER; i++ )
-        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f;
-
-    totsamp = 0;
-    lsum    = rsum = 0.;
-    return retval;
-}
-
-
-Float_t
-GetAlbumGain ( void )
-{
-    return analyzeResult ( B, sizeof(B)/sizeof(*B) );
-}
-
-/* end of replaygain_analysis.c */
--- a/src/flac/replaygain_analysis.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
- *  Copyright (C) 2001 David Robinson and Glen Sawyer
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- *  concept and filter values by David Robinson (David@Robinson.org)
- *    -- blame him if you think the idea is flawed
- *  coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA
- *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
- *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
- *
- *  For an explanation of the concepts and the basic algorithms involved, go to:
- *    http://www.replaygain.org/
- */
-
-#ifndef GAIN_ANALYSIS_H
-#define GAIN_ANALYSIS_H
-
-#include <stddef.h>
-
-#define GAIN_NOT_ENOUGH_SAMPLES  -24601
-#define GAIN_ANALYSIS_ERROR           0
-#define GAIN_ANALYSIS_OK              1
-
-#define INIT_GAIN_ANALYSIS_ERROR      0
-#define INIT_GAIN_ANALYSIS_OK         1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef float   Float_t;         /* Type used for filtering */
-extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */
-
-int     InitGainAnalysis ( long samplefreq );
-int     AnalyzeSamples   ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels );
-int		ResetSampleFrequency ( long samplefreq );
-Float_t   GetTitleGain     ( void );
-Float_t   GetAlbumGain     ( void );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GAIN_ANALYSIS_H */
--- a/src/flac/replaygain_synthesis.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,465 +0,0 @@
-/* replaygain_synthesis - Routines for applying ReplayGain to a signal
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-/*
- * This is an aggregation of pieces of code from John Edwards' WaveGain
- * program.  Mostly cosmetic changes were made; otherwise, the dithering
- * code is almost untouched and the gain processing was converted from
- * processing a whole file to processing chunks of samples.
- *
- * The original copyright notices for WaveGain's dither.c and wavegain.c
- * appear below:
- */
-/*
- * (c) 2002 John Edwards
- * mostly lifted from work by Frank Klemm
- * random functions for dithering.
- */
-/*
- * Copyright (C) 2002 John Edwards
- * Additional code by Magnus Holmgren and Gian-Carlo Pascutto
- */
-
-#include <string.h> /* for memset() */
-#include <math.h>
-#include "fast_float_math_hack.h"
-#include "replaygain_synthesis.h"
-#include "FLAC/assert.h"
-
-#if defined _MSC_VER
-#define FLAC__INLINE __inline
-#else
-#define FLAC__INLINE
-#endif
-
-/* adjust for compilers that can't understand using LL suffix for int64_t literals */
-#ifdef _MSC_VER
-#define FLAC__I64L(x) x
-#else
-#define FLAC__I64L(x) x##LL
-#endif
-
-
-/*
- * the following is based on parts of dither.c
- */
-
-
-/*
- *  This is a simple random number generator with good quality for audio purposes.
- *  It consists of two polycounters with opposite rotation direction and different
- *  periods. The periods are coprime, so the total period is the product of both.
- *
- *     -------------------------------------------------------------------------------------------------
- * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0|
- * |   -------------------------------------------------------------------------------------------------
- * |                                                                          |  |  |  |     |        |
- * |                                                                          +--+--+--+-XOR-+--------+
- * |                                                                                      |
- * +--------------------------------------------------------------------------------------+
- *
- *     -------------------------------------------------------------------------------------------------
- *     |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+
- *     -------------------------------------------------------------------------------------------------   |
- *       |  |           |  |                                                                               |
- *       +--+----XOR----+--+                                                                               |
- *                |                                                                                        |
- *                +----------------------------------------------------------------------------------------+
- *
- *
- *  The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481,
- *  which gives a period of 18.410.713.077.675.721.215. The result is the
- *  XORed values of both generators.
- */
-
-static unsigned int random_int_()
-{
-	static const unsigned char parity_[256] = {
-		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
-		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
-		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
-		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
-		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
-		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
-		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
-		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
-	};
-	static unsigned int r1_ = 1;
-	static unsigned int r2_ = 1;
-
-	unsigned int t1, t2, t3, t4;
-
-	/* Parity calculation is done via table lookup, this is also available
-	 * on CPUs without parity, can be implemented in C and avoid unpredictable
-	 * jumps and slow rotate through the carry flag operations.
-	 */
-	t3   = t1 = r1_;    t4   = t2 = r2_;
-	t1  &= 0xF5;        t2 >>= 25;
-	t1   = parity_[t1]; t2  &= 0x63;
-	t1 <<= 31;          t2   = parity_[t2];
-
-	return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 );
-}
-
-/* gives a equal distributed random number */
-/* between -2^31*mult and +2^31*mult */
-static double random_equi_(double mult)
-{
-	return mult * (int) random_int_();
-}
-
-/* gives a triangular distributed random number */
-/* between -2^32*mult and +2^32*mult */
-static double random_triangular_(double mult)
-{
-	return mult * ( (double) (int) random_int_() + (double) (int) random_int_() );
-}
-
-
-static const float  F44_0 [16 + 32] = {
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
-
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
-
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
-	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0
-};
-
-
-static const float  F44_1 [16 + 32] = {  /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */
-	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
-	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
-	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
-	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
-
-	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
-	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
-	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
-	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
-
-	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
-	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
-	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
-	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
-};
-
-
-static const float  F44_2 [16 + 32] = {  /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */
-	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
-	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
-	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
-	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
-
-	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
-	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
-	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
-	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
-
-	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
-	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
-	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
-	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
-};
-
-
-static const float  F44_3 [16 + 32] = {  /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */
-	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
-	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
-	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
-	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
-
-	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
-	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
-	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
-	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
-
-	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
-	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
-	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
-	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099
-};
-
-
-static double scalar16_(const float* x, const float* y)
-{
-	return
-		x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] +
-		x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] +
-		x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] +
-		x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15];
-}
-
-
-void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype)
-{
-	static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67,  0,  0 };
-	static const float*               F [] = { F44_0, F44_1, F44_2, F44_3 };
-
-	int index;
-
-	if (shapingtype < 0) shapingtype = 0;
-	if (shapingtype > 3) shapingtype = 3;
-	d->ShapingType = (NoiseShaping)shapingtype;
-	index = bits - 11 - shapingtype;
-	if (index < 0) index = 0;
-	if (index > 9) index = 9;
-
-	memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) );
-	memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) );
-
-	d->FilterCoeff = F [shapingtype];
-	d->Mask   = ((FLAC__uint64)-1) << (32 - bits);
-	d->Add    = 0.5     * ((1L << (32 - bits)) - 1);
-	d->Dither = 0.01f*default_dither[index] / (((FLAC__int64)1) << bits);
-	d->LastHistoryIndex = 0;
-}
-
-/*
- * the following is based on parts of wavegain.c
- */
-
-static FLAC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
-{
-	union {
-		double d;
-		FLAC__int64 i;
-	} doubletmp;
-	double Sum2;
-	FLAC__int64 val;
-
-#define ROUND64(x)   ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) )
-
-	if(do_dithering) {
-		if(shapingtype == 0) {
-			double  tmp = random_equi_(d->Dither);
-			Sum2 = tmp - d->LastRandomNumber [k];
-			d->LastRandomNumber [k] = (int)tmp;
-			Sum2 = Sum += Sum2;
-			val = ROUND64(Sum2) & d->Mask;
-		}
-		else {
-			Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i);
-			Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2;
-			Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i);
-			val = ROUND64(Sum2) & d->Mask;
-			d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
-		}
-		return val;
-	}
-	else
-		return ROUND64(Sum);
-
-#undef ROUND64
-}
-
-#if 0
-	float        peak = 0.f,
-	             new_peak,
-	             factor_clip
-	double       scale,
-	             dB;
-
-	...
-
-	peak is in the range -32768.0 .. 32767.0
-
-	/* calculate factors for ReplayGain and ClippingPrevention */
-	*track_gain = GetTitleGain() + settings->man_gain;
-	scale = (float) pow(10., *track_gain * 0.05);
-	if(settings->clip_prev) {
-		factor_clip  = (float) (32767./( peak + 1));
-		if(scale < factor_clip)
-			factor_clip = 1.f;
-		else
-			factor_clip /= scale;
-		scale *= factor_clip;
-	}
-	new_peak = (float) peak * scale;
-
-	dB = 20. * log10(scale);
-	*track_gain = (float) dB;
-
- 	const double scale = pow(10., (double)gain * 0.05);
-#endif
-
-
-size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
-{
-	static const FLAC__int32 conv_factors_[33] = {
-		-1, /* 0 bits-per-sample (not supported) */
-		-1, /* 1 bits-per-sample (not supported) */
-		-1, /* 2 bits-per-sample (not supported) */
-		-1, /* 3 bits-per-sample (not supported) */
-		268435456, /* 4 bits-per-sample */
-		134217728, /* 5 bits-per-sample */
-		67108864, /* 6 bits-per-sample */
-		33554432, /* 7 bits-per-sample */
-		16777216, /* 8 bits-per-sample */
-		8388608, /* 9 bits-per-sample */
-		4194304, /* 10 bits-per-sample */
-		2097152, /* 11 bits-per-sample */
-		1048576, /* 12 bits-per-sample */
-		524288, /* 13 bits-per-sample */
-		262144, /* 14 bits-per-sample */
-		131072, /* 15 bits-per-sample */
-		65536, /* 16 bits-per-sample */
-		32768, /* 17 bits-per-sample */
-		16384, /* 18 bits-per-sample */
-		8192, /* 19 bits-per-sample */
-		4096, /* 20 bits-per-sample */
-		2048, /* 21 bits-per-sample */
-		1024, /* 22 bits-per-sample */
-		512, /* 23 bits-per-sample */
-		256, /* 24 bits-per-sample */
-		128, /* 25 bits-per-sample */
-		64, /* 26 bits-per-sample */
-		32, /* 27 bits-per-sample */
-		16, /* 28 bits-per-sample */
-		8, /* 29 bits-per-sample */
-		4, /* 30 bits-per-sample */
-		2, /* 31 bits-per-sample */
-		1 /* 32 bits-per-sample */
-	};
-	static const FLAC__int64 hard_clip_factors_[33] = {
-		0, /* 0 bits-per-sample (not supported) */
-		0, /* 1 bits-per-sample (not supported) */
-		0, /* 2 bits-per-sample (not supported) */
-		0, /* 3 bits-per-sample (not supported) */
-		-8, /* 4 bits-per-sample */
-		-16, /* 5 bits-per-sample */
-		-32, /* 6 bits-per-sample */
-		-64, /* 7 bits-per-sample */
-		-128, /* 8 bits-per-sample */
-		-256, /* 9 bits-per-sample */
-		-512, /* 10 bits-per-sample */
-		-1024, /* 11 bits-per-sample */
-		-2048, /* 12 bits-per-sample */
-		-4096, /* 13 bits-per-sample */
-		-8192, /* 14 bits-per-sample */
-		-16384, /* 15 bits-per-sample */
-		-32768, /* 16 bits-per-sample */
-		-65536, /* 17 bits-per-sample */
-		-131072, /* 18 bits-per-sample */
-		-262144, /* 19 bits-per-sample */
-		-524288, /* 20 bits-per-sample */
-		-1048576, /* 21 bits-per-sample */
-		-2097152, /* 22 bits-per-sample */
-		-4194304, /* 23 bits-per-sample */
-		-8388608, /* 24 bits-per-sample */
-		-16777216, /* 25 bits-per-sample */
-		-33554432, /* 26 bits-per-sample */
-		-67108864, /* 27 bits-per-sample */
-		-134217728, /* 28 bits-per-sample */
-		-268435456, /* 29 bits-per-sample */
-		-536870912, /* 30 bits-per-sample */
-		-1073741824, /* 31 bits-per-sample */
-		(FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */
-	};
-	const FLAC__int32 conv_factor = conv_factors_[target_bps];
-	const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps];
-	/*
-	 * The integer input coming in has a varying range based on the
-	 * source_bps.  We want to normalize it to [-1.0, 1.0) so instead
-	 * of doing two multiplies on each sample, we just multiple
-	 * 'scale' by 1/(2^(source_bps-1))
-	 */
-	const double multi_scale = scale / (double)(1u << (source_bps-1));
-
-	FLAC__byte * const start = data_out;
-	unsigned i, channel;
-	const FLAC__int32 *input_;
-	double sample;
-	const unsigned bytes_per_sample = target_bps / 8;
-	const unsigned last_history_index = dither_context->LastHistoryIndex;
-	NoiseShaping noise_shaping = dither_context->ShapingType;
-	FLAC__int64 val64;
-	FLAC__int32 val32;
-	FLAC__int32 uval32;
-	const FLAC__uint32 twiggle = 1u << (target_bps - 1);
-
-	FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS);
-	FLAC__ASSERT(source_bps >= 4);
-	FLAC__ASSERT(target_bps >= 4);
-	FLAC__ASSERT(source_bps <= 32);
-	FLAC__ASSERT(target_bps < 32);
-	FLAC__ASSERT((target_bps & 7) == 0);
-
-	for(channel = 0; channel < channels; channel++) {
-		const unsigned incr = bytes_per_sample * channels;
-		data_out = start + bytes_per_sample * channel;
-		input_ = input[channel];
-		for(i = 0; i < wide_samples; i++, data_out += incr) {
-			sample = (double)input_[i] * multi_scale;
-
-			if(hard_limit) {
-				/* hard 6dB limiting */
-				if(sample < -0.5)
-					sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
-				else if(sample > 0.5)
-					sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
-			}
-			sample *= 2147483647.f;
-
-			val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor;
-
-			val32 = (FLAC__int32)val64;
-			if(val64 >= -hard_clip_factor)
-				val32 = (FLAC__int32)(-(hard_clip_factor+1));
-			else if(val64 < hard_clip_factor)
-				val32 = (FLAC__int32)hard_clip_factor;
-
-			uval32 = (FLAC__uint32)val32;
-			if (unsigned_data_out)
-				uval32 ^= twiggle;
-
-			if (little_endian_data_out) {
-				switch(target_bps) {
-					case 24:
-						data_out[2] = (FLAC__byte)(uval32 >> 16);
-						/* fall through */
-					case 16:
-						data_out[1] = (FLAC__byte)(uval32 >> 8);
-						/* fall through */
-					case 8:
-						data_out[0] = (FLAC__byte)uval32;
-						break;
-				}
-			}
-			else {
-				switch(target_bps) {
-					case 24:
-						data_out[0] = (FLAC__byte)(uval32 >> 16);
-						data_out[1] = (FLAC__byte)(uval32 >> 8);
-						data_out[2] = (FLAC__byte)uval32;
-						break;
-					case 16:
-						data_out[0] = (FLAC__byte)(uval32 >> 8);
-						data_out[1] = (FLAC__byte)uval32;
-						break;
-					case 8:
-						data_out[0] = (FLAC__byte)uval32;
-						break;
-				}
-			}
-		}
-	}
-	dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32;
-
-	return wide_samples * channels * (target_bps/8);
-}
--- a/src/flac/replaygain_synthesis.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* replaygain_synthesis - Routines for applying ReplayGain to a signal
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
-#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
-
-#include <stdlib.h> /* for size_t */
-#include "FLAC/ordinals.h"
-
-#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2
-
-typedef enum {
-	NOISE_SHAPING_NONE = 0,
-	NOISE_SHAPING_LOW = 1,
-	NOISE_SHAPING_MEDIUM = 2,
-	NOISE_SHAPING_HIGH = 3
-} NoiseShaping;
-
-typedef struct {
-	const float*  FilterCoeff;
-	FLAC__uint64  Mask;
-	double        Add;
-	float         Dither;
-	float         ErrorHistory     [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];  /* 16th order Noise shaping */
-	float         DitherHistory    [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];
-	int           LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS];
-	unsigned      LastHistoryIndex;
-	NoiseShaping  ShapingType;
-} DitherContext;
-
-void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype);
-
-/* scale = (float) pow(10., (double)replaygain * 0.05); */
-size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
-
-#endif
--- a/src/flac/tag.c	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2000,2001,2002,2003,2004,2005  Josh Coalson
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * Based on FLAC plugin.c and mpg123 plugin
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <glib.h>
-#include <audacious/plugin.h>
-#include <audacious/util.h>
-#include <audacious/titlestring.h>
-
-#include "FLAC/metadata.h"
-#include "plugin_common/tags.h"
-#include "charset.h"
-#include "configure.h"
-
-/*
- * Function local__extname (filename)
- *
- *    Return pointer within filename to its extenstion, or NULL if
- *    filename has no extension.
- *
- */
-static char *local__extname(const char *filename)
-{
-	char *ext = strrchr(filename, '.');
-
-	if (ext != NULL)
-		++ext;
-
-	return ext;
-}
-
-static char *local__getstr(char* str)
-{
-	if (str && strlen(str) > 0)
-		return g_strdup(str);
-	return NULL;
-}
-
-static int local__getnum(char* str)
-{
-	if (str && strlen(str) > 0)
-		return atoi(str);
-	return 0;
-}
-
-static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name)
-{
-	if (0 != tags) {
-		const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
-		if (0 != utf8) {
-			if(flac_cfg.title.convert_char_set)
-				return convert_from_utf8_to_user(utf8);
-			else
-				return strdup(utf8);
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Function flac_format_song_title (tag, filename)
- *
- *    Create song title according to `tag' and/or `filename' and
- *    return it.  The title must be subsequently freed using g_free().
- *
- */
-TitleInput *flac_get_tuple(char *filename)
-{
-	TitleInput *input = NULL;
-	FLAC__StreamMetadata *tags;
-	FLAC__StreamMetadata info;
-	char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description;
-	gchar *filename_proxy = g_strdup(filename);
-
-	FLAC_plugin__tags_get(filename_proxy, &tags);
-
-	title       = local__getfield(tags, "TITLE");
-	artist      = local__getfield(tags, "ARTIST");
-	performer   = local__getfield(tags, "PERFORMER");
-	album       = local__getfield(tags, "ALBUM");
-	date        = local__getfield(tags, "DATE");
-	tracknumber = local__getfield(tags, "TRACKNUMBER");
-	genre       = local__getfield(tags, "GENRE");
-	description = local__getfield(tags, "DESCRIPTION");
-
-	input = bmp_title_input_new();
-
-	input->performer = local__getstr(performer);
-	if(!input->performer)
-		input->performer = local__getstr(artist);
-	input->album_name = local__getstr(album);
-	input->track_name = local__getstr(title);
-	input->track_number = local__getnum(tracknumber);
-	input->year = local__getnum(date);
-	input->genre = local__getstr(genre);
-	input->comment = local__getstr(description);
-
-	input->file_name = g_path_get_basename(filename_proxy);
-	input->file_path = g_path_get_dirname(filename_proxy);
-	input->file_ext = local__extname(filename_proxy);
-
-        FLAC__metadata_get_streaminfo(filename, &info);
-
-	input->length = (unsigned)((double)info.data.stream_info.total_samples / (double)info.data.stream_info.sample_rate * 1000.0 + 0.5);
-
-	return input;
-}
-
-gchar *flac_format_song_title(gchar *filename)
-{
-	gchar *ret = NULL;
-	TitleInput *tuple = flac_get_tuple(filename);
-
-	ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), tuple);
-
-	if (!ret) {
-		/*
-		 * Format according to filename.
-		 */
-		ret = g_strdup(g_basename(filename));
-		if (local__extname(ret) != NULL)
-			*(local__extname(ret) - 1) = '\0';	/* removes period */
-	}
-
-	bmp_title_input_free(tuple);
-
-	return ret;
-}
--- a/src/flac/tag.h	Mon Oct 23 19:46:25 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-/* libxmms-flac - XMMS FLAC input plugin
- * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#ifndef __FLAC__PLUGIN_XMMS__TAG_H__
-#define __FLAC__PLUGIN_XMMS__TAG_H__
-
-TitleInput *flac_get_tuple(gchar * filename);
-gchar *flac_format_song_title(gchar * filename);
-
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/Makefile	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,39 @@
+include ../../mk/rules.mk
+include ../../mk/init.mk
+
+SUBDIRS = plugin_common
+
+noinst_HEADERS = \
+	charset.h \
+	configure.h \
+	http.h \
+	plugin.h \
+	tag.h \
+	fast_float_math_hack.h \
+	replaygain_analysis.h \
+	grabbag.h \
+	replaygain_synthesis.h
+
+OBJECTIVE_LIBS = libflac$(SHARED_SUFFIX)
+
+LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR)
+
+LIBADD = $(LIBFLAC_LIBS)  -L./plugin_common -lplugin_common
+
+SOURCES = \
+	charset.c \
+	configure.c \
+	fileinfo.c \
+	http.c \
+	plugin.c \
+	tag.c \
+	replaygain_synthesis.c \
+	replaygain.c \
+	replaygain_analysis.c \
+	file.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../.. $(LIBFLAC_CFLAGS)
+
+include ../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/charset.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,194 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * Almost from charset.c
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "plugin_common/charset.h"
+#include "plugin_common/locale_hack.h"
+#include "charset.h"
+#include "configure.h"
+
+
+/****************
+ * Declarations *
+ ****************/
+
+#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) )
+const CharsetInfo charset_trans_array[] = {
+	{N_("Arabic (IBM-864)"),                  "IBM864"        },
+	{N_("Arabic (ISO-8859-6)"),               "ISO-8859-6"    },
+	{N_("Arabic (Windows-1256)"),             "windows-1256"  },
+	{N_("Baltic (ISO-8859-13)"),              "ISO-8859-13"   },
+	{N_("Baltic (ISO-8859-4)"),               "ISO-8859-4"    },
+	{N_("Baltic (Windows-1257)"),             "windows-1257"  },
+	{N_("Celtic (ISO-8859-14)"),              "ISO-8859-14"   },
+	{N_("Central European (IBM-852)"),        "IBM852"        },
+	{N_("Central European (ISO-8859-2)"),     "ISO-8859-2"    },
+	{N_("Central European (Windows-1250)"),   "windows-1250"  },
+	{N_("Chinese Simplified (GB18030)"),      "gb18030"       },
+	{N_("Chinese Simplified (GB2312)"),       "GB2312"        },
+	{N_("Chinese Traditional (Big5)"),        "Big5"          },
+	{N_("Chinese Traditional (Big5-HKSCS)"),  "Big5-HKSCS"    },
+	{N_("Cyrillic (IBM-855)"),                "IBM855"        },
+	{N_("Cyrillic (ISO-8859-5)"),             "ISO-8859-5"    },
+	{N_("Cyrillic (ISO-IR-111)"),             "ISO-IR-111"    },
+	{N_("Cyrillic (KOI8-R)"),                 "KOI8-R"        },
+	{N_("Cyrillic (Windows-1251)"),           "windows-1251"  },
+	{N_("Cyrillic/Russian (CP-866)"),         "IBM866"        },
+	{N_("Cyrillic/Ukrainian (KOI8-U)"),       "KOI8-U"        },
+	{N_("English (US-ASCII)"),                "us-ascii"      },
+	{N_("Greek (ISO-8859-7)"),                "ISO-8859-7"    },
+	{N_("Greek (Windows-1253)"),              "windows-1253"  },
+	{N_("Hebrew (IBM-862)"),                  "IBM862"        },
+	{N_("Hebrew (Windows-1255)"),             "windows-1255"  },
+	{N_("Japanese (EUC-JP)"),                 "EUC-JP"        },
+	{N_("Japanese (ISO-2022-JP)"),            "ISO-2022-JP"   },
+	{N_("Japanese (Shift_JIS)"),              "Shift_JIS"     },
+	{N_("Korean (EUC-KR)"),                   "EUC-KR"        },
+	{N_("Nordic (ISO-8859-10)"),              "ISO-8859-10"   },
+	{N_("South European (ISO-8859-3)"),       "ISO-8859-3"    },
+	{N_("Thai (TIS-620)"),                    "TIS-620"       },
+	{N_("Turkish (IBM-857)"),                 "IBM857"        },
+	{N_("Turkish (ISO-8859-9)"),              "ISO-8859-9"    },
+	{N_("Turkish (Windows-1254)"),            "windows-1254"  },
+	{N_("Unicode (UTF-7)"),                   "UTF-7"         },
+	{N_("Unicode (UTF-8)"),                   "UTF-8"         },
+	{N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
+	{N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
+	{N_("Unicode (UTF-32BE)"),                "UTF-32BE"      },
+	{N_("Unicode (UTF-32LE)"),                "UTF-32LE"      },
+	{N_("Vietnamese (VISCII)"),               "VISCII"        },
+	{N_("Vietnamese (Windows-1258)"),         "windows-1258"  },
+	{N_("Visual Hebrew (ISO-8859-8)"),        "ISO-8859-8"    },
+	{N_("Western (IBM-850)"),                 "IBM850"        },
+	{N_("Western (ISO-8859-1)"),              "ISO-8859-1"    },
+	{N_("Western (ISO-8859-15)"),             "ISO-8859-15"   },
+	{N_("Western (Windows-1252)"),            "windows-1252"  }
+
+	/*
+	 * From this point, character sets aren't supported by iconv
+	 */
+#if 0
+	{N_("Arabic (IBM-864-I)"),                "IBM864i"              },
+	{N_("Arabic (ISO-8859-6-E)"),             "ISO-8859-6-E"         },
+	{N_("Arabic (ISO-8859-6-I)"),             "ISO-8859-6-I"         },
+	{N_("Arabic (MacArabic)"),                "x-mac-arabic"         },
+	{N_("Armenian (ARMSCII-8)"),              "armscii-8"            },
+	{N_("Central European (MacCE)"),          "x-mac-ce"             },
+	{N_("Chinese Simplified (GBK)"),          "x-gbk"                },
+	{N_("Chinese Simplified (HZ)"),           "HZ-GB-2312"           },
+	{N_("Chinese Traditional (EUC-TW)"),      "x-euc-tw"             },
+	{N_("Croatian (MacCroatian)"),            "x-mac-croatian"       },
+	{N_("Cyrillic (MacCyrillic)"),            "x-mac-cyrillic"       },
+	{N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian"      },
+	{N_("Farsi (MacFarsi)"),                  "x-mac-farsi"},
+	{N_("Greek (MacGreek)"),                  "x-mac-greek"          },
+	{N_("Gujarati (MacGujarati)"),            "x-mac-gujarati"       },
+	{N_("Gurmukhi (MacGurmukhi)"),            "x-mac-gurmukhi"       },
+	{N_("Hebrew (ISO-8859-8-E)"),             "ISO-8859-8-E"         },
+	{N_("Hebrew (ISO-8859-8-I)"),             "ISO-8859-8-I"         },
+	{N_("Hebrew (MacHebrew)"),                "x-mac-hebrew"         },
+	{N_("Hindi (MacDevanagari)"),             "x-mac-devanagari"     },
+	{N_("Icelandic (MacIcelandic)"),          "x-mac-icelandic"      },
+	{N_("Korean (JOHAB)"),                    "x-johab"              },
+	{N_("Korean (UHC)"),                      "x-windows-949"        },
+	{N_("Romanian (MacRomanian)"),            "x-mac-romanian"       },
+	{N_("Turkish (MacTurkish)"),              "x-mac-turkish"        },
+	{N_("User Defined"),                      "x-user-defined"       },
+	{N_("Vietnamese (TCVN)"),                 "x-viet-tcvn5712"      },
+	{N_("Vietnamese (VPS)"),                  "x-viet-vps"           },
+	{N_("Western (MacRoman)"),                "x-mac-roman"          },
+	/* charsets whithout posibly translatable names */
+	{"T61.8bit",                              "T61.8bit"             },
+	{"x-imap4-modified-utf7",                 "x-imap4-modified-utf7"},
+	{"x-u-escaped",                           "x-u-escaped"          },
+	{"windows-936",                           "windows-936"          }
+#endif
+};
+
+/*************
+ * Functions *
+ *************/
+
+/*
+ * Commons conversion functions
+ */
+char *convert_from_utf8_to_user(const char *string)
+{
+	return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set);
+}
+
+char *convert_from_user_to_utf8(const char *string)
+{
+	return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8");
+}
+
+GList *Charset_Create_List (void)
+{
+	GList *list = NULL;
+	guint i;
+
+	for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+		list = g_list_append(list,_(charset_trans_array[i].charset_title));
+	return list;
+}
+
+GList *Charset_Create_List_UTF8_Only (void)
+{
+	GList *list = NULL;
+
+	list = g_list_append(list,_(Charset_Get_Title_From_Name("UTF-8")));
+	return list;
+}
+
+
+/*
+ * Return charset_name from charset_title
+ */
+gchar *Charset_Get_Name_From_Title (const gchar *charset_title)
+{
+	guint i;
+
+	if (charset_title)
+		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+			if ( strcasecmp(_(charset_title),_(charset_trans_array[i].charset_title)) == 0 )
+				return charset_trans_array[i].charset_name;
+	return "";
+}
+
+
+/*
+ * Return charset_title from charset_name
+ */
+gchar *Charset_Get_Title_From_Name (const gchar *charset_name)
+{
+	guint i;
+
+	if (charset_name)
+		for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++)
+			if ( strcasecmp(charset_name,charset_trans_array[i].charset_name) == 0 )
+				return _(charset_trans_array[i].charset_title);
+	return "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/charset.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,56 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * Almost from charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __CHARSET_H__
+#define __CHARSET_H__
+
+
+/***************
+ * Declaration *
+ ***************/
+
+typedef struct {
+	gchar *charset_title;
+	gchar *charset_name;
+} CharsetInfo;
+
+/* translated charset titles */
+extern const CharsetInfo charset_trans_array[];
+
+/**************
+ * Prototypes *
+ **************/
+
+/*
+ * The returned strings are malloc()ed an must be free()d by the caller
+ */
+char *convert_from_utf8_to_user(const char *string);
+char *convert_from_user_to_utf8(const char *string);
+
+GList *Charset_Create_List (void);
+GList *Charset_Create_List_UTF8_Only (void);
+gchar *Charset_Get_Name_From_Title (const gchar *charset_title);
+gchar *Charset_Get_Title_From_Name (const gchar *charset_name);
+
+#endif /* __CHARSET_H__ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/configure.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,685 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *          and prefs.c - 2000/05/06
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 2000-2002  Jerome Couderc <j.couderc@ifrance.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+#include <audacious/configdb.h>
+#include <audacious/dirbrowser.h>
+#include <audacious/titlestring.h>
+#include <audacious/util.h>
+#include <audacious/plugin.h>
+
+#include "plugin_common/locale_hack.h"
+#include "replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */
+#include "charset.h"
+#include "configure.h"
+
+/*
+ * Initialize Global Valueable
+ */
+flac_config_t flac_cfg = {
+	/* title */
+	{
+		FALSE, /* tag_override */
+		NULL, /* tag_format */
+		FALSE, /* convert_char_set */
+		NULL /* user_char_set */
+	},
+	/* stream */
+	{
+		100 /* KB */, /* http_buffer_size */
+		50, /* http_prebuffer */
+		FALSE, /* use_proxy */
+		"", /* proxy_host */
+		0, /* proxy_port */
+		FALSE, /* proxy_use_auth */
+		"", /* proxy_user */
+		"", /* proxy_pass */
+		FALSE, /* save_http_stream */
+		"", /* save_http_path */
+		FALSE, /* cast_title_streaming */
+		FALSE /* use_udp_channel */
+	},
+	/* output */
+	{
+		/* replaygain */
+		{
+			FALSE, /* enable */
+			TRUE, /* album_mode */
+			0, /* preamp */
+			FALSE /* hard_limit */
+		},
+		/* resolution */
+		{
+			/* normal */
+			{
+				TRUE /* dither_24_to_16 */
+			},
+			/* replaygain */
+			{
+				TRUE, /* dither */
+				NOISE_SHAPING_LOW, /* noise_shaping */
+				16 /* bps_out */
+			}
+		}
+	}
+};
+
+
+static GtkWidget *flac_configurewin = NULL;
+static GtkWidget *vbox, *notebook;
+
+static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc;
+static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry;
+static GtkWidget *replaygain_enable, *replaygain_album_mode;
+static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit;
+static GtkObject *replaygain_preamp;
+static GtkWidget *resolution_normal_dither_24_to_16;
+static GtkWidget *resolution_replaygain_dither;
+static GtkWidget *resolution_replaygain_noise_shaping_frame;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_none;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_low;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_medium;
+static GtkWidget *resolution_replaygain_noise_shaping_radio_high;
+static GtkWidget *resolution_replaygain_bps_out_frame;
+static GtkWidget *resolution_replaygain_bps_out_radio_16bps;
+static GtkWidget *resolution_replaygain_bps_out_radio_24bps;
+
+static GtkObject *streaming_size_adj, *streaming_pre_adj;
+static GtkWidget *streaming_save_use, *streaming_save_entry;
+#ifdef FLAC_ICECAST
+static GtkWidget *streaming_cast_title, *streaming_udp_title;
+#endif
+static GtkWidget *streaming_save_dirbrowser;
+static GtkWidget *streaming_save_hbox;
+
+static const gchar *gtk_entry_get_text_1 (GtkWidget *widget);
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data);
+static void configure_destroy(GtkWidget * w, gpointer data);
+
+static void flac_configurewin_ok(GtkWidget * widget, gpointer data)
+{
+	ConfigDb *db;
+
+	(void)widget, (void)data; /* unused arguments */
+	g_free(flac_cfg.title.tag_format);
+	flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry)));
+	flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry));
+
+	db = bmp_cfg_db_open();
+	/* title */
+	bmp_cfg_db_set_bool(db, "flac", "title.tag_override", flac_cfg.title.tag_override);
+	bmp_cfg_db_set_string(db, "flac", "title.tag_format", flac_cfg.title.tag_format);
+	bmp_cfg_db_set_bool(db, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set);
+	bmp_cfg_db_set_string(db, "flac", "title.user_char_set", flac_cfg.title.user_char_set);
+	/* output */
+	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable);
+	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode);
+	bmp_cfg_db_set_int(db, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp);
+	bmp_cfg_db_set_bool(db, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit);
+	bmp_cfg_db_set_bool(db, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16);
+	bmp_cfg_db_set_bool(db, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither);
+	bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping);
+	bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out);
+	/* streaming */
+	flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value;
+	flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value;
+
+	flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+
+	if (flac_cfg.stream.save_http_path != NULL)
+		g_free(flac_cfg.stream.save_http_path);
+
+	flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry)));
+
+#ifdef FLAC_ICECAST
+	flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title));
+	flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title));
+#endif
+
+	bmp_cfg_db_set_int(db, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size);
+	bmp_cfg_db_set_int(db, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer);
+	bmp_cfg_db_set_bool(db, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream);
+	bmp_cfg_db_set_string(db, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path);
+#ifdef FLAC_ICECAST
+	bmp_cfg_db_set_bool(db, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming);
+	bmp_cfg_db_set_bool(db, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel);
+#endif
+
+	bmp_cfg_db_close(db);
+	gtk_widget_destroy(flac_configurewin);
+}
+
+static void configure_destroy(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+}
+
+static void title_tag_override_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override));
+
+	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+
+}
+
+static void convert_char_set_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set));
+
+	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+}
+
+static void replaygain_enable_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable));
+
+	gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable);
+	gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable);
+	gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable);
+}
+
+static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode));
+}
+
+static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit));
+}
+
+static void replaygain_preamp_cb(GtkWidget *widget, gpointer data)
+{
+	GString *gstring = g_string_new("");
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5);
+
+	g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp);
+	gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str));
+}
+
+static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16));
+}
+
+static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither));
+
+	gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither);
+}
+
+static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.noise_shaping =
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 :
+		0
+	;
+}
+
+static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data)
+{
+	(void)widget, (void)data; /* unused arguments */
+	flac_cfg.output.resolution.replaygain.bps_out =
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 :
+		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 :
+		16
+	;
+}
+
+static void streaming_save_dirbrowser_cb(gchar * dir)
+{
+	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir);
+}
+
+static void streaming_save_browse_cb(GtkWidget * w, gpointer data)
+{
+	(void) w;
+	(void) data;
+	if (!streaming_save_dirbrowser)
+	{
+		streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"),
+								    flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb);
+		gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser);
+		gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin));
+		gtk_widget_show(streaming_save_dirbrowser);
+	}
+}
+
+static void streaming_save_use_cb(GtkWidget * w, gpointer data)
+{
+	gboolean save_stream;
+	(void) w;
+	(void) data;
+
+	save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use));
+
+	gtk_widget_set_sensitive(streaming_save_hbox, save_stream);
+}
+
+
+void FLAC_XMMS__configure(void)
+{
+	GtkWidget *title_frame, *title_tag_vbox, *title_tag_label;
+	GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame;
+	GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox;
+	GtkWidget *resolution_replaygain_noise_shaping_vbox;
+	GtkWidget *resolution_replaygain_bps_out_vbox;
+	GtkWidget *label, *hbox;
+	GtkWidget *bbox, *ok, *cancel;
+	GList *list;
+
+	GtkWidget *streaming_vbox;
+	GtkWidget *streaming_buf_frame, *streaming_buf_hbox;
+	GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin;
+	GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin;
+	GtkWidget *streaming_save_frame, *streaming_save_vbox;
+	GtkWidget *streaming_save_label, *streaming_save_browse;
+#ifdef FLAC_ICECAST
+	GtkWidget *streaming_cast_frame, *streaming_cast_vbox;
+#endif
+
+	if (flac_configurewin != NULL) {
+		gdk_window_raise(flac_configurewin->window);
+		return;
+	}
+	flac_configurewin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin);
+	gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin);
+	gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration"));
+	gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE);
+	gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10);
+
+	vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox);
+
+	notebook = gtk_notebook_new();
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+	/* Title config.. */
+
+	title_frame = gtk_frame_new(_("Tag Handling"));
+	gtk_container_border_width(GTK_CONTAINER(title_frame), 5);
+
+	title_tag_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox);
+
+	/* Convert Char Set */
+
+	convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set);
+	gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", (GCallback)convert_char_set_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0);
+	/*  Combo boxes... */
+	hbox = gtk_hbox_new(FALSE,4);
+	gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox);
+	label = gtk_label_new(_("Convert character set from :"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	fileCharacterSetEntry = gtk_combo_new();
+	gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0);
+
+	label = gtk_label_new (_("to :"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	userCharacterSetEntry = gtk_combo_new();
+	gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0);
+
+	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE);
+	gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE);
+	gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE);
+	gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE);
+
+	list = Charset_Create_List();
+	gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only());
+	gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list);
+	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set));
+	gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE);
+	gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set);
+
+	/* Override Tagging Format */
+
+	title_tag_override = gtk_check_button_new_with_label(_("Override generic titles"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override);
+	gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", (GCallback)title_tag_override_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0);
+
+	title_tag_box = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0);
+
+	title_tag_label = gtk_label_new(_("Title format:"));
+	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0);
+
+	title_tag_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format);
+	gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0);
+
+	title_desc = xmms_titlestring_descriptions("pafFetnygc", 2);
+	gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override);
+	gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title")));
+
+	/* Output config.. */
+
+	output_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(output_vbox), 5);
+
+	/* replaygain */
+
+	replaygain_frame = gtk_frame_new(_("ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5);
+	gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0);
+
+	replaygain_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox);
+
+	replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable);
+	gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", (GCallback)replaygain_enable_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0);
+
+	replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode);
+	gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", (GCallback)replaygain_album_mode_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new(FALSE,3);
+	gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox);
+	label = gtk_label_new(_("Preamp:"));
+	gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0);
+	replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0);
+	gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", (GCallback)replaygain_preamp_cb, NULL);
+	replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp));
+	gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE);
+	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0);
+	replaygain_preamp_label = gtk_label_new(_("0 dB"));
+	gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0);
+	gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp));
+
+	replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit);
+	gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", (GCallback)replaygain_hard_limit_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0);
+
+	replaygain_enable_cb(replaygain_enable, NULL);
+
+	/* resolution */
+
+	resolution_frame = gtk_frame_new(_("Resolution"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5);
+	gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0);
+
+	resolution_hbox = gtk_hbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox);
+
+	resolution_normal_frame = gtk_frame_new(_("Without ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0);
+
+	resolution_normal_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox);
+
+	resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16);
+	gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", (GCallback)resolution_normal_dither_24_to_16_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0);
+
+	resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0);
+
+	resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox);
+
+	resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", (GCallback)resolution_replaygain_dither_cb, NULL);
+	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new(FALSE, 10);
+	gtk_container_border_width(GTK_CONTAINER(hbox), 5);
+	gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0);
+
+	resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5);
+	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0);
+
+	resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new();
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox);
+
+	resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 0)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none);
+
+	resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 1)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low);
+
+	resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 2)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium);
+
+	resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high"));
+	if(flac_cfg.output.resolution.replaygain.noise_shaping == 3)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high);
+
+	resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to"));
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5);
+	gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0);
+
+	resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new();
+	gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox);
+
+	resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps"));
+	if(flac_cfg.output.resolution.replaygain.bps_out == 16)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps);
+
+	resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps"));
+	if(flac_cfg.output.resolution.replaygain.bps_out == 24)
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE);
+	gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL);
+	gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps);
+
+	resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL);
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output")));
+
+	/* Streaming */
+
+	streaming_vbox = gtk_vbox_new(FALSE, 0);
+
+	streaming_buf_frame = gtk_frame_new(_("Buffering:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0);
+
+	streaming_buf_hbox = gtk_hbox_new(TRUE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5);
+	gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox);
+
+	streaming_size_box = gtk_hbox_new(FALSE, 5);
+	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */
+	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0);
+	streaming_size_label = gtk_label_new(_("Buffer size (kb):"));
+	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0);
+	streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4);
+	streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0);
+	gtk_widget_set_usize(streaming_size_spin, 60, -1);
+	gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0);
+
+	streaming_pre_box = gtk_hbox_new(FALSE, 5);
+	/*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */
+	gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0);
+	streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):"));
+	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0);
+	streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1);
+	streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0);
+	gtk_widget_set_usize(streaming_pre_spin, 60, -1);
+	gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0);
+
+	/*
+	 * Save to disk config.
+	 */
+	streaming_save_frame = gtk_frame_new(_("Save stream to disk:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0);
+
+	streaming_save_vbox = gtk_vbox_new(FALSE, 5);
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5);
+	gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox);
+
+	streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream);
+	gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0);
+
+	streaming_save_hbox = gtk_hbox_new(FALSE, 5);
+	gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream);
+	gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0);
+
+	streaming_save_label = gtk_label_new(_("Path:"));
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0);
+
+	streaming_save_entry = gtk_entry_new();
+	gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path);
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0);
+
+	streaming_save_browse = gtk_button_new_with_label(_("Browse"));
+	gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL);
+	gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0);
+
+#ifdef FLAC_ICECAST
+	streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:"));
+	gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5);
+	gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0);
+
+	streaming_cast_vbox = gtk_vbox_new(5, FALSE);
+	gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox);
+
+	streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming);
+	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0);
+
+	streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel"));
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel);
+	gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0);
+#endif
+
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming")));
+
+	/* Buttons */
+
+	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(flac_configurewin_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(flac_configurewin));
+	GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+	gtk_widget_show_all(flac_configurewin);
+}
+
+void FLAC_XMMS__aboutbox()
+{
+	static GtkWidget *about_window;
+
+	if (about_window)
+		gdk_window_raise(about_window->window);
+	else
+	{
+		about_window = xmms_show_message(
+			_("About Flac Plugin"),
+			_("Flac Plugin by Josh Coalson\n"
+			  "contributions by\n"
+			  "......\n"
+			  "......\n"
+			  "and\n"
+			  "Daisuke Shimamura\n"
+			  "Visit http://flac.sourceforge.net/"),
+			_("Ok"), FALSE, NULL, NULL);
+		gtk_signal_connect(GTK_OBJECT(about_window), "destroy",
+				   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+				   &about_window);
+	}
+}
+
+/*
+ * Get text of an Entry or a ComboBox
+ */
+static const gchar *gtk_entry_get_text_1 (GtkWidget *widget)
+{
+	if (GTK_IS_COMBO(widget))
+	{
+		return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry));
+	}else if (GTK_IS_ENTRY(widget))
+	{
+		return gtk_entry_get_text(GTK_ENTRY(widget));
+	}else
+	{
+		return NULL;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/configure.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,77 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * Based on mpg123 plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __CONFIGURE_H__
+#define __CONFIGURE_H__
+
+#include <glib.h>
+
+typedef struct {
+	struct {
+		gboolean tag_override;
+		gchar *tag_format;
+		gboolean convert_char_set;
+		gchar *user_char_set;
+	} title;
+
+	struct {
+		gint http_buffer_size;
+		gint http_prebuffer;
+		gboolean use_proxy; 
+		gchar *proxy_host;
+		gint proxy_port;
+		gboolean proxy_use_auth;
+		gchar *proxy_user;
+		gchar	*proxy_pass;
+		gboolean save_http_stream;
+		gchar *save_http_path;
+		gboolean cast_title_streaming;
+		gboolean use_udp_channel;
+	} stream;
+
+	struct {
+		struct {
+			gboolean enable;
+			gboolean album_mode;
+			gint preamp;
+			gboolean hard_limit;
+		} replaygain;
+		struct {
+			struct {
+				gboolean dither_24_to_16;
+			} normal;
+			struct {
+				gboolean dither;
+				gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */
+				gint bps_out;
+			} replaygain;
+		} resolution;
+	} output;
+} flac_config_t;
+
+extern flac_config_t flac_cfg;
+
+extern void FLAC_XMMS__configure(void);
+extern void FLAC_XMMS__aboutbox();
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/fast_float_math_hack.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,39 @@
+#   ifdef __ICL /* only Intel C compiler has fmath ??? */
+
+    #include <mathf.h>
+
+/* Nearest integer, absolute value, etc. */
+
+    #define ceil ceilf
+    #define fabs fabsf
+    #define floor floorf
+    #define fmod fmodf
+    #define rint rintf
+    #define hypot hypotf
+
+/* Power functions */
+
+    #define pow powf
+    #define sqrt sqrtf
+
+/* Exponential and logarithmic functions */
+
+    #define exp expf
+    #define log logf
+    #define log10 log10f
+
+/* Trigonometric functions */
+
+    #define acos acosf
+    #define asin asinf
+    #define atan atanf
+    #define cos cosf
+    #define sin sinf
+    #define tan tanf
+
+/* Hyperbolic functions */
+    #define cosh coshf
+    #define sinh sinhf
+    #define tanh tanhf
+
+#   endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/file.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,142 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod(), _setmode(), unlink() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+#ifdef __CYGWIN__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#if defined _WIN32 && !defined __CYGWIN__
+#else
+#include <unistd.h> /* for unlink() */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strrchr() */
+#include "grabbag.h"
+
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
+{
+	struct stat srcstat;
+	struct utimbuf srctime;
+
+	if(0 == stat(srcpath, &srcstat)) {
+		srctime.actime = srcstat.st_atime;
+		srctime.modtime = srcstat.st_mtime;
+		(void)chmod(destpath, srcstat.st_mode);
+		(void)utime(destpath, &srctime);
+	}
+}
+
+off_t grabbag__file_get_filesize(const char *srcpath)
+{
+	struct stat srcstat;
+
+	if(0 == stat(srcpath, &srcstat))
+		return srcstat.st_size;
+	else
+		return -1;
+}
+
+const char *grabbag__file_get_basename(const char *srcpath)
+{
+	const char *p;
+
+	p = strrchr(srcpath, '/');
+	if(0 == p) {
+		p = strrchr(srcpath, '\\');
+		if(0 == p)
+			return srcpath;
+	}
+	return ++p;
+}
+
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
+{
+	struct stat stats;
+
+	if(0 == stat(filename, &stats)) {
+#if !defined _MSC_VER && !defined __MINGW32__
+		if(read_only) {
+			stats.st_mode &= ~S_IWUSR;
+			stats.st_mode &= ~S_IWGRP;
+			stats.st_mode &= ~S_IWOTH;
+		}
+		else {
+			stats.st_mode |= S_IWUSR;
+		}
+#else
+		if(read_only)
+			stats.st_mode &= ~S_IWRITE;
+		else
+			stats.st_mode |= S_IWRITE;
+#endif
+		if(0 != chmod(filename, stats.st_mode))
+			return false;
+	}
+	else
+		return false;
+
+	return true;
+}
+
+FLAC__bool grabbag__file_remove_file(const char *filename)
+{
+	return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename);
+}
+
+FILE *grabbag__file_get_binary_stdin()
+{
+	/* if something breaks here it is probably due to the presence or
+	 * absence of an underscore before the identifiers 'setmode',
+	 * 'fileno', and/or 'O_BINARY'; check your system header files.
+	 */
+#if defined _MSC_VER || defined __MINGW32__
+	_setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__
+	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
+	setmode(_fileno(stdin), _O_BINARY);
+#endif
+
+	return stdin;
+}
+
+FILE *grabbag__file_get_binary_stdout()
+{
+	/* if something breaks here it is probably due to the presence or
+	 * absence of an underscore before the identifiers 'setmode',
+	 * 'fileno', and/or 'O_BINARY'; check your system header files.
+	 */
+#if defined _MSC_VER || defined __MINGW32__
+	_setmode(_fileno(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+	/* almost certainly not needed for any modern Cygwin, but let's be safe... */
+	setmode(_fileno(stdout), _O_BINARY);
+#endif
+
+	return stdout;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/fileinfo.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,500 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1999,2000  Håvard Kvålen
+ *  Copyright (C) 2002,2003,2004,2005,2006  Daisuke Shimamura
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h> /* for strlen() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <gtk/gtk.h>
+
+#include "audacious/util.h"
+#include "FLAC/metadata.h"
+#include "charset.h"
+#include "configure.h"
+#include "plugin_common/locale_hack.h"
+#include "plugin_common/replaygain.h"
+#include "plugin_common/tags.h"
+
+static GtkWidget *window = NULL;
+static GList *genre_list = NULL;
+static GtkWidget *filename_entry, *tag_frame;
+static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry;
+static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak;
+static GtkWidget *genre_combo;
+static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate;
+
+static gchar *current_filename = NULL;
+static FLAC__StreamMetadata *tags_ = NULL;
+
+static const gchar *vorbis_genres[] =
+{
+	N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
+	N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
+	N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
+	N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
+	N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
+	N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
+	N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
+	N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
+	N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
+	N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"),
+	N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
+	N_("Meditative"), N_("Instrumental Pop"),
+	N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
+	N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
+	N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
+	N_("Southern Rock"), N_("Comedy"), N_("Cult"),
+	N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
+	N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
+	N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
+	N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
+	N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
+	N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
+	N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
+	N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
+	N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
+	N_("Gothic Rock"), N_("Progressive Rock"),
+	N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
+	N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
+	N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
+	N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
+	N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
+	N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
+	N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
+	N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
+	N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
+	N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
+	N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
+	N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
+	N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
+	N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
+	N_("Contemporary Christian"), N_("Christian Rock"),
+	N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
+	N_("Anime"), N_("JPop"), N_("Synthpop")
+};
+
+static void label_set_text(GtkWidget * label, char *str, ...)
+{
+	va_list args;
+	gchar *tempstr;
+
+	va_start(args, str);
+	tempstr = g_strdup_vprintf(str, args);
+	va_end(args);
+
+	gtk_label_set_text(GTK_LABEL(label), tempstr);
+	g_free(tempstr);
+}
+
+static void set_entry_tag(GtkEntry * entry, const char * utf8)
+{
+	if(utf8) {
+		if(flac_cfg.title.convert_char_set) {
+			char *text = convert_from_utf8_to_user(utf8);
+			gtk_entry_set_text(entry, text);
+			free(text);
+		}
+		else
+			gtk_entry_set_text(entry, utf8);
+	}
+	else
+		gtk_entry_set_text(entry, "");
+}
+
+static void get_entry_tag(GtkEntry * entry, const char *name)
+{
+	gchar *text;
+	char *utf8;
+
+	text = g_strdup(gtk_entry_get_text(entry));
+	if (!text || strlen(text) == 0) 
+	{
+		g_free(text);
+		return;
+	}
+	if(flac_cfg.title.convert_char_set)
+		utf8 = convert_from_user_to_utf8(text);
+	else
+		utf8 = text;
+
+	FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0);
+
+	if(flac_cfg.title.convert_char_set)
+		free(utf8);
+	g_free(text);
+}
+
+static void show_tag()
+{
+	set_entry_tag(GTK_ENTRY(title_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE"));
+	set_entry_tag(GTK_ENTRY(artist_entry)                 , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST"));
+	set_entry_tag(GTK_ENTRY(album_entry)                  , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM"));
+	set_entry_tag(GTK_ENTRY(date_entry)                   , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE"));
+	set_entry_tag(GTK_ENTRY(tracknum_entry)               , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER"));
+	set_entry_tag(GTK_ENTRY(comment_entry)                , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION"));
+	set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE"));
+}
+
+static void save_tag(GtkWidget * w, gpointer data)
+{
+	(void)w;
+	(void)data;
+
+	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+	FLAC_plugin__tags_delete_tag(tags_, "DATE");
+	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+	get_entry_tag(GTK_ENTRY(title_entry)                  , "TITLE");
+	get_entry_tag(GTK_ENTRY(artist_entry)                 , "ARTIST");
+	get_entry_tag(GTK_ENTRY(album_entry)                  , "ALBUM");
+	get_entry_tag(GTK_ENTRY(date_entry)                   , "DATE");
+	get_entry_tag(GTK_ENTRY(tracknum_entry)               , "TRACKNUMBER");
+	get_entry_tag(GTK_ENTRY(comment_entry)                , "DESCRIPTION");
+	get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE");
+
+	FLAC_plugin__tags_set(current_filename, tags_);
+	gtk_widget_destroy(window);
+}
+
+static void remove_tag(GtkWidget * w, gpointer data)
+{
+	(void)w;
+	(void)data;
+	
+	FLAC_plugin__tags_delete_tag(tags_, "TITLE");
+	FLAC_plugin__tags_delete_tag(tags_, "ARTIST");
+	FLAC_plugin__tags_delete_tag(tags_, "ALBUM");
+	FLAC_plugin__tags_delete_tag(tags_, "DATE");
+	FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER");
+	FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION");
+	FLAC_plugin__tags_delete_tag(tags_, "GENRE");
+
+	FLAC_plugin__tags_set(current_filename, tags_);
+	gtk_widget_destroy(window);
+}
+
+static void show_file_info()
+{
+	FLAC__StreamMetadata streaminfo;
+	struct stat _stat;
+
+	gtk_label_set_text(GTK_LABEL(flac_samplerate), "");
+	gtk_label_set_text(GTK_LABEL(flac_channels), "");
+	gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), "");
+	gtk_label_set_text(GTK_LABEL(flac_blocksize), "");
+	gtk_label_set_text(GTK_LABEL(flac_filesize), "");
+	gtk_label_set_text(GTK_LABEL(flac_samples), "");
+	gtk_label_set_text(GTK_LABEL(flac_bitrate), "");
+
+	if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) {
+		return;
+	}
+
+	label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate);
+	label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels);
+	label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample);
+	if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize)
+		label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize);
+	else
+		label_set_text(flac_blocksize, _("Blocksize: variable\n  min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize);
+
+	if (streaminfo.data.stream_info.total_samples)
+		label_set_text(flac_samples, _("Samples: %llu\nLength: %d:%.2d"),
+				streaminfo.data.stream_info.total_samples,
+				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60),
+				(int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60));
+
+	if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) {
+#if _FILE_OFFSET_BITS == 64
+		label_set_text(flac_filesize, _("Filesize: %lld B"), _stat.st_size);
+#else
+		label_set_text(flac_filesize, _("Filesize: %ld B"), _stat.st_size);
+#endif
+		if (streaminfo.data.stream_info.total_samples)
+			label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"),
+					8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate),
+					100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples));
+	}
+}
+
+static void show_replaygain()
+{
+	/* known limitation: If only one of gain and peak is set, neither will be shown. This is true for
+	 * both track and album replaygain tags. Written so it will be easy to fix, with some trouble.  */
+
+	gtk_label_set_text(GTK_LABEL(replaygain_reference), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_track_gain), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_album_gain), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_track_peak), "");
+	gtk_label_set_text(GTK_LABEL(replaygain_album_peak), "");
+
+	double reference, track_gain, track_peak, album_gain, album_peak;
+	FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set;
+
+	FLAC_plugin__replaygain_get_from_file(
+		current_filename,
+		&reference, &reference_set,
+		&track_gain, &track_gain_set,
+		&album_gain, &album_gain_set,
+		&track_peak, &track_peak_set,
+		&album_peak, &album_peak_set
+	);
+
+	if(reference_set)
+		label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference);
+	if(track_gain_set)
+		label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain);
+	if(album_gain_set)
+		label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain);
+	if(track_peak_set)
+		label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak);
+	if(album_peak_set)
+		label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak);
+}
+
+void FLAC_XMMS__file_info_box(char *filename)
+{
+	unsigned i;
+	gchar *title;
+	gchar *filename_utf8;
+
+	if (!window)
+	{
+		GtkWidget *vbox, *hbox, *left_vbox, *table;
+		GtkWidget *flac_frame, *flac_box;
+		GtkWidget *label, *filename_hbox;
+		GtkWidget *bbox, *save, *remove, *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(gtk_widget_destroyed), &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);
+
+		tag_frame = gtk_frame_new(_("Tag:"));
+		gtk_box_pack_start(GTK_BOX(left_vbox), tag_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(tag_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(_("Date:"));
+		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);
+
+		date_entry = gtk_entry_new();
+		gtk_widget_set_usize(date_entry, 40, -1);
+		gtk_table_attach(GTK_TABLE(table), date_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), TRUE);
+
+		if (!genre_list)
+		{
+			for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++)
+				genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]);
+			genre_list = g_list_prepend(genre_list, "");
+			genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp);
+		}
+		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_tag), 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= gtk_button_new_with_label(_("Remove Tag"));
+		gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL);
+		GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT);
+		gtk_box_pack_start(GTK_BOX(bbox), remove, 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);
+
+		flac_frame = gtk_frame_new(_("FLAC Info:"));
+		gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0);
+
+		flac_box = gtk_vbox_new(FALSE, 5);
+		gtk_container_add(GTK_CONTAINER(flac_frame), flac_box);
+		gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10);
+		gtk_box_set_spacing(GTK_BOX(flac_box), 0);
+
+		flac_samplerate = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0);
+
+		flac_channels = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0);
+
+		flac_bits_per_sample = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0);
+
+		flac_blocksize = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0);
+
+		flac_filesize = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0);
+
+		flac_samples = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0);
+
+		flac_bitrate = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0);
+
+		replaygain_reference = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0);
+
+		replaygain_track_gain = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0);
+
+		replaygain_album_gain = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0);
+
+		replaygain_track_peak = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0);
+
+		replaygain_album_peak = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0);
+		gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT);
+		gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0);
+
+		gtk_widget_show_all(window);
+	}
+
+	if(current_filename)
+		g_free(current_filename);
+	if(!(current_filename = g_strdup(filename)))
+		return;
+
+	filename_utf8 = filename_to_utf8(current_filename);
+	title = g_strdup_printf(_("File Info - %s"), g_basename(filename_utf8));
+	gtk_window_set_title(GTK_WINDOW(window), title);
+	g_free(title);
+
+	gtk_entry_set_text(GTK_ENTRY(filename_entry), filename_utf8);
+	gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1);
+
+	g_free(filename_utf8);
+
+	if(tags_)
+		FLAC_plugin__tags_destroy(&tags_);
+
+	FLAC_plugin__tags_get(current_filename, &tags_);
+
+	show_tag();
+	show_file_info();
+	show_replaygain();
+
+	gtk_widget_set_sensitive(tag_frame, TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/grabbag.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,33 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef SHARE__GRABBAG_H
+#define SHARE__GRABBAG_H
+
+#include <FLAC/all.h>
+#include "plugin_common/all.h"
+
+
+/* These can't be included by themselves, only from within grabbag.h */
+#include "grabbag/cuesheet.h"
+#include "grabbag/file.h"
+#include "grabbag/replaygain.h"
+#include "grabbag/seektable.h"
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/grabbag/cuesheet.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,42 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__CUESHEET_H
+#define GRABBAG__CUESHEET_H
+
+#include <stdio.h>
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames);
+void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames);
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/grabbag/file.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,54 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/* Convenience routines for manipulating files */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__FILE_H
+#define GRABAG__FILE_H
+
+#include <sys/types.h> /* for off_t */
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath);
+off_t grabbag__file_get_filesize(const char *srcpath);
+const char *grabbag__file_get_basename(const char *srcpath);
+
+/* read_only == false means "make file writable by user"
+ * read_only == true means "make file read-only for everyone"
+ */
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only);
+
+/* attempts to make writable before unlinking */
+FLAC__bool grabbag__file_remove_file(const char *filename);
+
+/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */
+FILE *grabbag__file_get_binary_stdin();
+FILE *grabbag__file_get_binary_stdout();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/grabbag/replaygain.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,72 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006 Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/*
+ * This wraps the replaygain_analysis lib, which is LGPL.  This wrapper
+ * allows analysis of different input resolutions by automatically
+ * scaling the input signal
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__REPLAYGAIN_H
+#define GRABBAG__REPLAYGAIN_H
+
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
+
+/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples);
+
+void grabbag__replaygain_get_album(float *gain, float *peak);
+void grabbag__replaygain_get_title(float *gain, float *peak);
+
+/* These three functions return an error string on error, or NULL if successful */
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block);
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak);
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/grabbag/seektable.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,38 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+/* Convenience routines for working with seek tables */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__SEEKTABLE_H
+#define GRABAG__SEEKTABLE_H
+
+#include "FLAC/format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/http.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,897 @@
+/*  XMMS - Cross-platform multimedia player
+ *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+/* modified for FLAC support by Steven Richman (2003) */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <glib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <audacious/plugin.h>
+#include <audacious/util.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "configure.h"
+#include "plugin_common/locale_hack.h"
+#include "FLAC/format.h"
+#include "plugin.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
+#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
+
+static gchar *icy_name = NULL;
+static gint icy_metaint = 0;
+
+extern InputPlugin flac_ip;
+
+#undef DEBUG_UDP
+
+/* Static udp channel functions */
+static int udp_establish_listener (gint *sock);
+static int udp_check_for_data(gint sock);
+
+static char *flac_http_get_title(char *url);
+
+static gboolean prebuffering, going, eof = FALSE;
+static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
+static guint64 buffer_read = 0;
+static gchar *buffer;
+static guint64 offset;
+static GThread *thread;
+static GtkWidget *error_dialog = NULL;
+
+static FILE *output_file = NULL;
+
+#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
+
+/* Encode the string S of length LENGTH to base64 format and place it
+   to STORE.  STORE will be 0-terminated, and must point to a writable
+   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
+static void base64_encode (const gchar *s, gchar *store, gint length)
+{
+	/* Conversion table.  */
+	static gchar tbl[64] = {
+		'A','B','C','D','E','F','G','H',
+		'I','J','K','L','M','N','O','P',
+		'Q','R','S','T','U','V','W','X',
+		'Y','Z','a','b','c','d','e','f',
+		'g','h','i','j','k','l','m','n',
+		'o','p','q','r','s','t','u','v',
+		'w','x','y','z','0','1','2','3',
+		'4','5','6','7','8','9','+','/'
+	};
+	gint i;
+	guchar *p = (guchar *)store;
+
+	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
+	for (i = 0; i < length; i += 3)
+	{
+		*p++ = tbl[s[0] >> 2];
+		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
+		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
+		*p++ = tbl[s[2] & 0x3f];
+		s += 3;
+	}
+	/* Pad the result if necessary...  */
+	if (i == length + 1)
+		*(p - 1) = '=';
+	else if (i == length + 2)
+		*(p - 1) = *(p - 2) = '=';
+	/* ...and zero-terminate it.  */
+	*p = '\0';
+}
+
+/* Create the authentication header contents for the `Basic' scheme.
+   This is done by encoding the string `USER:PASS' in base64 and
+   prepending `HEADER: Basic ' to it.  */
+static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
+{
+	gchar *t1, *t2, *res;
+	gint len1 = strlen (user) + 1 + strlen (passwd);
+	gint len2 = BASE64_LENGTH (len1);
+
+	t1 = g_strdup_printf("%s:%s", user, passwd);
+	t2 = g_malloc0(len2 + 1);
+	base64_encode (t1, t2, len1);
+	res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
+	g_free(t2);
+	g_free(t1);
+	
+	return res;
+}
+
+static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
+{
+	gchar *h, *p, *pt, *f, *temp, *ptr;
+
+	temp = g_strdup(url);
+	ptr = temp;
+
+	if (!strncasecmp("http://", ptr, 7))
+		ptr += 7;
+	h = strchr(ptr, '@');
+	f = strchr(ptr, '/');
+	if (h != NULL && (!f || h < f))
+	{
+		*h = '\0';
+		p = strchr(ptr, ':');
+		if (p != NULL && p < h)
+		{
+			*p = '\0';
+			p++;
+			*pass = g_strdup(p);
+		}
+		else
+			*pass = NULL;
+		*user = g_strdup(ptr);
+		h++;
+		ptr = h;
+	}
+	else
+	{
+		*user = NULL;
+		*pass = NULL;
+		h = ptr;
+	}
+	pt = strchr(ptr, ':');
+	if (pt != NULL && (f == NULL || pt < f))
+	{
+		*pt = '\0';
+		*port = atoi(pt + 1);
+	}
+	else
+	{
+		if (f)
+			*f = '\0';
+		*port = 80;
+	}
+	*host = g_strdup(h);
+	
+	if (f)
+		*filename = g_strdup(f + 1);
+	else
+		*filename = NULL;
+	g_free(temp);
+}
+
+void flac_http_close(void)
+{
+	going = FALSE;
+
+	g_thread_join(thread);
+	g_free(icy_name);
+	icy_name = NULL;
+}
+
+
+static gint http_used(void)
+{
+	if (wr_index >= rd_index)
+		return wr_index - rd_index;
+	return buffer_length - (rd_index - wr_index);
+}
+
+static gint http_free(void)
+{
+	if (rd_index > wr_index)
+		return (rd_index - wr_index) - 1;
+	return (buffer_length - (wr_index - rd_index)) - 1;
+}
+
+static void http_wait_for_data(gint bytes)
+{
+	while ((prebuffering || http_used() < bytes) && !eof && going)
+		xmms_usleep(10000);
+}
+
+static void show_error_message(gchar *error)
+{
+	if(!error_dialog)
+	{
+		GDK_THREADS_ENTER();
+		error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
+						 NULL, NULL);
+		g_signal_connect(G_OBJECT(error_dialog),
+				   "destroy",
+				   G_CALLBACK(gtk_widget_destroyed),
+				   &error_dialog);
+		GDK_THREADS_LEAVE();
+	}
+}
+
+int flac_http_read(gpointer data, gint length)
+{
+	gint len, cnt, off = 0, meta_len, meta_off = 0, i;
+	gchar *meta_data, **tags, *temp, *title;
+	if (length > buffer_length) {
+		length = buffer_length;
+	}
+
+	http_wait_for_data(length);
+
+	if (!going)
+		return 0;
+	len = min(http_used(), length);
+
+	while (len && http_used())
+	{
+		if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
+		{
+			meta_len = *((guchar *) buffer + rd_index) * 16;
+			rd_index = (rd_index + 1) % buffer_length;
+			if (meta_len > 0)
+			{
+				http_wait_for_data(meta_len);
+				meta_data = g_malloc0(meta_len);
+				if (http_used() >= meta_len)
+				{
+					while (meta_len)
+					{
+						cnt = min(meta_len, buffer_length - rd_index);
+						memcpy(meta_data + meta_off, buffer + rd_index, cnt);
+						rd_index = (rd_index + cnt) % buffer_length;
+						meta_len -= cnt;
+						meta_off += cnt;
+					}
+					tags = g_strsplit(meta_data, "';", 0);
+
+					for (i = 0; tags[i]; i++)
+					{
+						if (!strncasecmp(tags[i], "StreamTitle=", 12))
+						{
+							temp = g_strdup(tags[i] + 13);
+							title = g_strdup_printf("%s (%s)", temp, icy_name);
+							set_track_info(title, -1);
+							g_free(title);
+							g_free(temp);
+						}
+
+					}
+					g_strfreev(tags);
+
+				}
+				g_free(meta_data);
+			}
+			if (!http_used())
+				http_wait_for_data(length - off);
+			cnt = min3(len, buffer_length - rd_index, http_used());
+		}
+		else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
+			cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
+		else
+			cnt = min3(len, buffer_length - rd_index, http_used());
+		if (output_file)
+			fwrite(buffer + rd_index, 1, cnt, output_file);
+
+		memcpy((gchar *)data + off, buffer + rd_index, cnt);
+		rd_index = (rd_index + cnt) % buffer_length;
+		buffer_read += cnt;
+		len -= cnt;
+		off += cnt;
+	}
+	if (!off) {
+		fprintf(stderr, "returning zero\n");
+	}
+	return off;
+}
+
+static gboolean http_check_for_data(void)
+{
+
+	fd_set set;
+	struct timeval tv;
+	gint ret;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 20000;
+	FD_ZERO(&set);
+	FD_SET(sock, &set);
+	ret = select(sock + 1, &set, NULL, NULL, &tv);
+	if (ret > 0)
+		return TRUE;
+	return FALSE;
+}
+
+gint flac_http_read_line(gchar * buf, gint size)
+{
+	gint i = 0;
+
+	while (going && i < size - 1)
+	{
+		if (http_check_for_data())
+		{
+			if (read(sock, buf + i, 1) <= 0)
+				return -1;
+			if (buf[i] == '\n')
+				break;
+			if (buf[i] != '\r')
+				i++;
+		}
+	}
+	if (!going)
+		return -1;
+	buf[i] = '\0';
+	return i;
+}
+
+/* returns the file descriptor of the socket, or -1 on error */
+static int http_connect (gchar *url_, gboolean head, guint64 offset)
+{
+	gchar line[1024], *user, *pass, *host, *filename,
+	     *status, *url, *temp, *file;
+	gchar *chost;
+	gint cnt, error, port, cport;
+	guint err_len;
+	gboolean redirect;
+	int udp_sock = 0;
+	fd_set set;
+	struct hostent *hp;
+	struct sockaddr_in address;
+	struct timeval tv;
+
+	url = g_strdup (url_);
+
+	do
+	{
+		redirect=FALSE;
+	
+		g_strstrip(url);
+
+		parse_url(url, &user, &pass, &host, &port, &filename);
+
+		if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
+			temp = g_strconcat(url, "/", NULL);
+		else
+			temp = g_strdup(url);
+		g_free(url);
+		url = temp;
+
+		chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
+		cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
+
+		sock = socket(AF_INET, SOCK_STREAM, 0);
+		fcntl(sock, F_SETFL, O_NONBLOCK);
+		address.sin_family = AF_INET;
+
+		status = g_strdup_printf(_("LOOKING UP %s"), chost);
+		flac_ip.set_info_text(status);
+		g_free(status);
+
+		if (!(hp = gethostbyname(chost)))
+		{
+			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
+			show_error_message(status);
+			g_free(status);
+
+			flac_ip.set_info_text(NULL);
+			eof = TRUE;
+		}
+
+		if (!eof)
+		{
+			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
+			address.sin_port = (gint) g_htons(cport);
+
+			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
+			flac_ip.set_info_text(status);
+			g_free(status);
+			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
+			{
+				if (errno != EINPROGRESS)
+				{
+					status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
+					show_error_message(status);
+					g_free(status);
+
+					flac_ip.set_info_text(NULL);
+					eof = TRUE;
+				}
+			}
+			while (going)
+			{
+				tv.tv_sec = 0;
+				tv.tv_usec = 10000;
+				FD_ZERO(&set);
+				FD_SET(sock, &set);
+				if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
+				{
+					err_len = sizeof (error);
+					getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
+					if (error)
+					{
+						status = g_strdup_printf(_("Couldn't connect to host %s"),
+									 chost);
+						show_error_message(status);
+						g_free(status);
+
+						flac_ip.set_info_text(NULL);
+						eof = TRUE;
+						
+					}
+					break;
+				}
+			}
+			if (!eof)
+			{
+				gchar *auth = NULL, *proxy_auth = NULL;
+				gchar udpspace[30];
+				int udp_port;
+
+				if (flac_cfg.stream.use_udp_channel)
+				{
+					udp_port = udp_establish_listener (&udp_sock);
+					if (udp_port > 0) 
+						sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port);
+					else
+						udp_sock = 0;
+				}
+					
+				if(user && pass)
+					auth = basic_authentication_encode(user, pass, "Authorization");
+
+				if (flac_cfg.stream.use_proxy)
+				{
+					file = g_strdup(url);
+					if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
+					{
+						proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
+											 flac_cfg.stream.proxy_pass,
+											 "Proxy-Authorization");
+					}
+				}
+				else
+					file = g_strconcat("/", filename, NULL);
+
+				temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
+						       "Host: %s\r\n"
+						       "User-Agent: %s/%s\r\n"
+						       "%s%s%s%s",
+						       file, host, "Reference FLAC Player", FLAC__VERSION_STRING, 
+						       proxy_auth ? proxy_auth : "", auth ? auth : "",
+						       flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
+						       flac_cfg.stream.use_udp_channel ? udpspace : "");
+				if (offset && !head) {
+					gchar *temp_dead = temp;
+					temp = g_strconcat ("%sRange: %ll-\r\n", temp, offset, NULL);
+					fprintf (stderr, "%s", temp);
+					g_free (temp_dead);
+				}
+				
+				g_free(file);
+				if(proxy_auth)
+					g_free(proxy_auth);
+				if(auth)
+					g_free(auth);
+				write(sock, temp, strlen(temp));
+				write(sock, "\r\n", 2);
+				g_free(temp);
+				flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
+				while (going && !eof)
+				  {
+					if (http_check_for_data())
+					{
+						if (flac_http_read_line(line, 1024))
+						{
+							status = strchr(line, ' ');
+							if (status)
+							{
+								if (status[1] == '2')
+									break;
+								else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
+								{
+									while(going)
+									{
+										if(http_check_for_data())
+										{
+											if((cnt = flac_http_read_line(line, 1024)) != -1)
+											{
+												if(!cnt)
+													break;
+												if(!strncmp(line, "Location:", 9))
+												{
+													g_free(url);
+													url = g_strdup(line+10);
+												}
+											}
+											else
+											{
+												eof=TRUE;
+												flac_ip.set_info_text(NULL);
+												break;
+											}
+										}
+									}			
+									redirect=TRUE;
+									break;
+								}
+								else
+								{
+									status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
+									show_error_message(status);
+									g_free(status);
+									break;
+								}
+							}
+						}
+						else
+						{
+							eof = TRUE;
+							flac_ip.set_info_text(NULL);
+						}
+					}
+				}
+
+				while (going && !redirect)
+				{
+					if (http_check_for_data())
+					{
+						if ((cnt = flac_http_read_line(line, 1024)) != -1)
+						{
+							if (!cnt)
+								break;
+							if (!strncmp(line, "icy-name:", 9))
+								icy_name = g_strdup(line + 9);
+							else if (!strncmp(line, "x-audiocast-name:", 17))
+								icy_name = g_strdup(line + 17);
+							if (!strncmp(line, "icy-metaint:", 12))
+								icy_metaint = atoi(line + 12);
+							if (!strncmp(line, "x-audiocast-udpport:", 20)) {
+#ifdef DEBUG_UDP
+								fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
+#endif
+								/*udp_serverport = atoi (line + 20);*/
+							}
+							
+						}
+						else
+						{
+							eof = TRUE;
+							flac_ip.set_info_text(NULL);
+							break;
+						}
+					}
+				}
+			}
+		}
+	
+		if(redirect)
+		{
+			if (output_file)
+			{
+				fclose(output_file);
+				output_file = NULL;
+			}
+			close(sock);
+		}
+
+		g_free(user);
+		g_free(pass);
+		g_free(host);
+		g_free(filename);
+	} while(redirect);
+
+	g_free(url);
+	return eof ? -1 : sock;
+}
+
+static void *http_buffer_loop(void *arg)
+{
+	gchar *status, *url, *temp, *file;
+	gint cnt, written;
+	int udp_sock = 0;
+
+	url = (gchar *) arg;
+	sock = http_connect (url, false, offset);
+	
+	if (sock >= 0 && flac_cfg.stream.save_http_stream) {
+		gchar *output_name;
+		file = flac_http_get_title(url);
+		output_name = file;
+		if (!strncasecmp(output_name, "http://", 7))
+			output_name += 7;
+		temp = strrchr(output_name, '.');
+		if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
+			*temp = '\0';
+
+		while ((temp = strchr(output_name, '/')))
+			*temp = '_';
+		output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
+
+		g_free(file);
+
+		output_file = fopen(output_name, "wb");
+		g_free(output_name);
+	}
+
+	while (going)
+	{
+
+		if (!http_used() && !flac_ip.output->buffer_playing())
+		{
+			prebuffering = TRUE;
+			flac_ip.set_status_buffering(TRUE);
+		}
+		if (http_free() > 0 && !eof)
+		{
+			if (http_check_for_data())
+			{
+				cnt = min(http_free(), buffer_length - wr_index);
+				if (cnt > 1024)
+					cnt = 1024;
+				written = read(sock, buffer + wr_index, cnt);
+				if (written <= 0)
+				{
+					eof = TRUE;
+					if (prebuffering)
+					{
+						prebuffering = FALSE;
+						flac_ip.set_status_buffering(FALSE);
+
+						flac_ip.set_info_text(NULL);
+					}
+
+				}
+				else
+					wr_index = (wr_index + written) % buffer_length;
+			}
+
+			if (prebuffering)
+			{
+				if (http_used() > prebuffer_length)
+				{
+					prebuffering = FALSE;
+					flac_ip.set_status_buffering(FALSE);
+					flac_ip.set_info_text(NULL);
+				}
+				else
+				{
+					status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
+					flac_ip.set_info_text(status);
+					g_free(status);
+				}
+
+			}
+		}
+		else
+			xmms_usleep(10000);
+
+		if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
+			if (udp_check_for_data(udp_sock) < 0)
+			{
+				close(udp_sock);
+				udp_sock = 0;
+			}
+	}
+	if (output_file)
+	{
+		fclose(output_file);
+		output_file = NULL;
+	}
+	if (sock >= 0) {
+		close(sock);
+	}
+	if (udp_sock != 0)
+		close(udp_sock);
+
+	g_free(buffer);
+	g_free(url);
+	
+	g_thread_exit(NULL);
+	return NULL; /* avoid compiler warning */
+}
+
+int flac_http_open(gchar * _url, guint64 _offset)
+{
+	gchar *url;
+
+	url = g_strdup(_url);
+
+	rd_index = 0;
+	wr_index = 0;
+	buffer_length = flac_cfg.stream.http_buffer_size * 1024;
+	prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
+	buffer_read = 0;
+	icy_metaint = 0;
+	prebuffering = TRUE;
+	flac_ip.set_status_buffering(TRUE);
+	going = TRUE;
+	eof = FALSE;
+	buffer = g_malloc(buffer_length);
+	offset = _offset;
+
+	thread = g_thread_create((GThreadFunc)http_buffer_loop, url, TRUE, NULL);
+
+	return 0;
+}
+
+char *flac_http_get_title(char *url)
+{
+	if (icy_name)
+		return g_strdup(icy_name);
+	if (g_basename(url) && strlen(g_basename(url)) > 0)
+		return g_strdup(g_basename(url));
+	return g_strdup(url);
+}
+
+/* Start UDP Channel specific stuff */
+
+/* Find a good local udp port and bind udp_sock to it, return the port */
+static int udp_establish_listener(int *sock)
+{
+	struct sockaddr_in sin;
+	socklen_t sinlen = sizeof (struct sockaddr_in);
+	
+#ifdef DEBUG_UDP
+	fprintf (stderr,"Establishing udp listener\n");
+#endif
+	
+	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener(): unable to create socket");
+		return -1;
+	}
+
+	memset(&sin, 0, sinlen);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
+			
+	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+
+	memset(&sin, 0, sinlen);
+	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
+	{
+		g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
+		close(*sock);
+		return -1;
+	}
+
+#ifdef DEBUG_UDP
+	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+#endif
+	
+	return g_ntohs(sin.sin_port);
+}
+
+static int udp_check_for_data(int sock)
+{
+	char buf[1025], **lines;
+	char *valptr;
+	gchar *title;
+	gint len, i;
+	struct sockaddr_in from;
+	socklen_t fromlen;
+
+	fromlen = sizeof(struct sockaddr_in);
+	
+	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
+	{
+		if (errno != EAGAIN)
+		{
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
+			return -1;
+		}
+		return 0;
+	}
+	buf[len] = '\0';
+#ifdef DEBUG_UDP
+	fprintf (stderr,"Received: [%s]\n", buf);
+#endif
+	lines = g_strsplit(buf, "\n", 0);
+	if (!lines)
+		return 0;
+	
+	for (i = 0; lines[i]; i++)
+	{
+		while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
+		       (lines[i][strlen(lines[i]) - 1] == '\r'))
+			lines[i][strlen(lines[i]) - 1] = '\0';
+		
+		valptr = strchr(lines[i], ':');
+		
+		if (!valptr)
+			continue;
+		else
+			valptr++;
+		
+		g_strstrip(valptr);
+		if (!strlen(valptr))
+			continue;
+		
+		if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
+		{
+			title = g_strdup_printf ("%s (%s)", valptr, icy_name);
+			if (going)
+				set_track_info(title, -1);
+			g_free (title);
+		}
+
+#if 0
+		else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
+		{
+			if (atoi(valptr) != -1)
+				set_track_info(NULL, atoi(valptr));
+		}
+#endif
+				
+		else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
+		{
+			/* set_track_info(title, -1); */
+/*  			xmms_show_message(_("Message"), valptr, _("Ok"), */
+/*  					  FALSE, NULL, NULL); */
+			g_message("Stream_message: %s", valptr);
+		}
+
+#if 0
+		/* Use this to direct your webbrowser.. yeah right.. */
+		else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
+		{
+			if (lasturl && g_strcmp (valptr, lasturl))
+			{
+				c_message (stderr, "Song URL: %s\n", valptr);
+				g_free (lasturl);
+				lasturl = g_strdup (valptr);
+			}
+		}
+#endif
+		else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
+		{
+			gchar obuf[60];
+			sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr));
+			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
+			{
+				g_log(NULL, G_LOG_LEVEL_WARNING,
+				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
+			}
+#ifdef DEBUG_UDP
+			else
+				fprintf(stderr,"Sent ack: %s", obuf);
+			fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
+#endif
+		}
+	}
+	g_strfreev(lines);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/http.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,26 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __HTTP_H__
+#define __HTTP_H__
+
+extern int flac_http_open(gchar * url, guint64 offset);
+extern void flac_http_close(void);
+extern int flac_http_read(gpointer data, gint length);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,718 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "audacious/plugin.h"
+#include "audacious/output.h"
+#include "audacious/util.h"
+#include "audacious/configdb.h"
+#include "audacious/titlestring.h"
+#include "audacious/vfs.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "FLAC/all.h"
+#include "plugin_common/all.h"
+#include "grabbag.h"
+#include "replaygain_synthesis.h"
+#include "configure.h"
+#include "charset.h"
+#include "http.h"
+#include "tag.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+extern void FLAC_XMMS__file_info_box(char *filename);
+
+typedef struct {
+	FLAC__bool abort_flag;
+	FLAC__bool is_playing;
+	FLAC__bool is_http_source;
+	FLAC__bool eof;
+	FLAC__bool play_thread_open; /* if true, is_playing must also be true */
+	FLAC__uint64 total_samples;
+	unsigned bits_per_sample;
+	unsigned channels;
+	unsigned sample_rate;
+	int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */
+	gchar *title;
+	AFormat sample_format;
+	unsigned sample_format_bytes_per_sample;
+	int seek_to_in_sec;
+	FLAC__bool has_replaygain;
+	double replay_scale;
+	DitherContext dither_context;
+} stream_data_struct;
+
+static void FLAC_XMMS__init();
+static int  FLAC_XMMS__is_our_file(char *filename);
+static void FLAC_XMMS__play_file(char *filename);
+static void FLAC_XMMS__stop();
+static void FLAC_XMMS__pause(short p);
+static void FLAC_XMMS__seek(int time);
+static int  FLAC_XMMS__get_time();
+static void FLAC_XMMS__cleanup();
+static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
+
+static void *play_loop_(void *arg);
+
+static FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder);
+static void safe_decoder_finish_(FLAC__StreamDecoder *decoder);
+static void safe_decoder_delete_(FLAC__StreamDecoder *decoder);
+
+static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+InputPlugin flac_ip =
+{
+	NULL,
+	NULL,
+	NULL,
+	FLAC_XMMS__init,
+	FLAC_XMMS__aboutbox,
+	FLAC_XMMS__configure,
+	FLAC_XMMS__is_our_file,
+	NULL,
+	FLAC_XMMS__play_file,
+	FLAC_XMMS__stop,
+	FLAC_XMMS__pause,
+	FLAC_XMMS__seek,
+	NULL,
+	FLAC_XMMS__get_time,
+	NULL,
+	NULL,
+	FLAC_XMMS__cleanup,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	FLAC_XMMS__get_song_info,
+	FLAC_XMMS__file_info_box,
+	NULL,
+	flac_get_tuple
+};
+
+#define SAMPLES_PER_WRITE 512
+#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8))
+static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE];
+static unsigned sample_buffer_first_, sample_buffer_last_;
+
+static FLAC__StreamDecoder *decoder_ = 0, *decoder2 = 0;
+static stream_data_struct stream_data_;
+static GThread *decode_thread_;
+static FLAC__bool audio_error_ = false;
+static FLAC__bool is_big_endian_host_;
+
+#define BITRATE_HIST_SEGMENT_MSEC 500
+/* 500ms * 50 = 25s should be enough */
+#define BITRATE_HIST_SIZE 50
+static unsigned bitrate_history_[BITRATE_HIST_SIZE];
+
+#ifdef SUPPORT_ATTRIBUTE_VISIBILITY
+InputPlugin *get_iplugin_info() __attribute__((visibility("default")));
+#endif
+
+InputPlugin *get_iplugin_info()
+{
+	flac_ip.description = g_strdup_printf(_("FLAC Audio Plugin"));
+	return &flac_ip;
+}
+
+void set_track_info(const char* title, int length_in_msec)
+{
+	if (stream_data_.is_playing) {
+		flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+	}
+}
+
+static gchar* homedir()
+{
+	gchar *result;
+	char *env_home = getenv("HOME");
+	if (env_home) {
+		result = g_strdup (env_home);
+	} else {
+		uid_t uid = getuid();
+		struct passwd *pwent;
+		do {
+			pwent = getpwent();
+		} while (pwent && pwent->pw_uid != uid);
+		result = pwent ? g_strdup (pwent->pw_dir) : NULL;
+		endpwent();
+	}
+	return result;
+}
+
+static FLAC__bool is_http_source(const char *source)
+{
+	return 0 == strncasecmp(source, "http://", 7);
+}
+
+void FLAC_XMMS__init()
+{
+	ConfigDb *db;
+	FLAC__uint32 test = 1;
+	gchar *tmp;
+
+	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
+
+	flac_cfg.title.tag_override = FALSE;
+	if (flac_cfg.title.tag_format)
+		g_free(flac_cfg.title.tag_format);
+	flac_cfg.title.convert_char_set = FALSE;
+
+	db = bmp_cfg_db_open();
+
+	/* title */
+
+	bmp_cfg_db_get_bool(db, "flac", "title.tag_override", &flac_cfg.title.tag_override);
+
+	if(!bmp_cfg_db_get_string(db, "flac", "title.tag_format", &flac_cfg.title.tag_format))
+		flac_cfg.title.tag_format = g_strdup("%p - %t");
+
+	bmp_cfg_db_get_bool(db, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set);
+
+	if(!bmp_cfg_db_get_string(db, "flac", "title.user_char_set", &flac_cfg.title.user_char_set))
+		flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current();
+
+	/* replaygain */
+
+	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable);
+
+	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode);
+
+	if(!bmp_cfg_db_get_int(db, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp))
+		flac_cfg.output.replaygain.preamp = 0;
+
+	bmp_cfg_db_get_bool(db, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit);
+
+	bmp_cfg_db_get_bool(db, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16);
+	bmp_cfg_db_get_bool(db, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither);
+
+	if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping))
+		flac_cfg.output.resolution.replaygain.noise_shaping = 1;
+
+	if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out))
+		flac_cfg.output.resolution.replaygain.bps_out = 16;
+
+	/* stream */
+
+	bmp_cfg_db_get_int(db, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size);
+	bmp_cfg_db_get_int(db, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer);
+	bmp_cfg_db_get_bool(db, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream);
+	if (!bmp_cfg_db_get_string(db, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) ||
+		 ! *flac_cfg.stream.save_http_path) {
+	  /* TODO: Is this a memory leak ?? */
+	  /*
+		if (flac_cfg.stream.save_http_path)
+			g_free (flac_cfg.stream.save_http_path);
+	  */
+		flac_cfg.stream.save_http_path = homedir();
+	}
+	bmp_cfg_db_get_bool(db, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming);
+	bmp_cfg_db_get_bool(db, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel);
+
+	bmp_cfg_db_get_bool(db, NULL, "use_proxy", &flac_cfg.stream.use_proxy);
+	bmp_cfg_db_get_string(db, NULL, "proxy_host", &flac_cfg.stream.proxy_host);
+	bmp_cfg_db_get_string(db, NULL, "proxy_port", &tmp);
+
+	bmp_cfg_db_get_bool(db, NULL, "proxy_use_auth", &flac_cfg.stream.proxy_use_auth);
+	bmp_cfg_db_get_string(db, NULL, "proxy_user", &flac_cfg.stream.proxy_user);
+	bmp_cfg_db_get_string(db, NULL, "proxy_pass", &flac_cfg.stream.proxy_pass);
+
+	decoder_ = FLAC__stream_decoder_new();
+	bmp_cfg_db_close(db);
+}
+
+int FLAC_XMMS__is_our_file(char *filename)
+{
+	FILE *f;
+	FLAC__StreamMetadata streaminfo;
+
+	if(!is_http_source(filename)) {
+		if(0 == (f = fopen(filename, "r")))
+			return 0;
+		fclose(f);
+		if(FLAC__metadata_get_streaminfo(filename, &streaminfo))
+			return 1;
+		return 0;
+	}
+
+	if(!safe_decoder_init_(filename, decoder2))
+		return 0;
+
+	safe_decoder_finish_(decoder2);   
+	return 1;
+}
+
+void FLAC_XMMS__play_file(char *filename)
+{
+	FILE *f;
+
+	sample_buffer_first_ = sample_buffer_last_ = 0;
+	audio_error_ = false;
+	stream_data_.abort_flag = false;
+	stream_data_.is_playing = false;
+	stream_data_.is_http_source = is_http_source(filename);
+	stream_data_.eof = false;
+	stream_data_.play_thread_open = false;
+	stream_data_.has_replaygain = false;
+
+	if(!is_http_source(filename)) {
+		if(0 == (f = fopen(filename, "r")))
+			return;
+		fclose(f);
+	}
+
+	if(decoder_ == 0)
+		return;
+
+	if(!safe_decoder_init_(filename, decoder_))
+		return;
+
+	if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) {
+		if(flac_cfg.output.resolution.replaygain.bps_out == 8) {
+			stream_data_.sample_format = FMT_U8;
+			stream_data_.sample_format_bytes_per_sample = 1;
+		}
+		else if(flac_cfg.output.resolution.replaygain.bps_out == 16) {
+			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+			stream_data_.sample_format_bytes_per_sample = 2;
+		}
+		else {
+			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+			fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out);
+			safe_decoder_finish_(decoder_);
+			return;
+		}
+	}
+	else {
+		if(stream_data_.bits_per_sample == 8) {
+			stream_data_.sample_format = FMT_U8;
+			stream_data_.sample_format_bytes_per_sample = 1;
+		}
+		else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) {
+			stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE;
+			stream_data_.sample_format_bytes_per_sample = 2;
+		}
+		else {
+			/*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */
+			fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", stream_data_.bits_per_sample);
+			safe_decoder_finish_(decoder_);
+			return;
+		}
+	}
+	FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping);
+	stream_data_.is_playing = true;
+
+	if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) {
+		audio_error_ = true;
+		safe_decoder_finish_(decoder_);
+		return;
+	}
+
+	stream_data_.title = flac_format_song_title(filename);
+	flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels);
+
+	stream_data_.seek_to_in_sec = -1;
+	stream_data_.play_thread_open = true;
+	decode_thread_ = g_thread_create((GThreadFunc)play_loop_, NULL, TRUE, NULL);
+}
+
+void FLAC_XMMS__stop()
+{
+	if(stream_data_.is_playing) {
+		stream_data_.is_playing = false;
+		if(stream_data_.play_thread_open) {
+			stream_data_.play_thread_open = false;
+			g_thread_join(decode_thread_);
+		}
+		flac_ip.output->close_audio();
+		safe_decoder_finish_(decoder_);
+	}
+}
+
+void FLAC_XMMS__pause(short p)
+{
+	flac_ip.output->pause(p);
+}
+
+void FLAC_XMMS__seek(int time)
+{
+	if(!stream_data_.is_http_source) {
+		stream_data_.seek_to_in_sec = time;
+		stream_data_.eof = false;
+
+		while(stream_data_.seek_to_in_sec != -1)
+			xmms_usleep(10000);
+	}
+}
+
+int FLAC_XMMS__get_time()
+{
+	if(audio_error_)
+		return -2;
+	if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing()))
+		return -1;
+	else
+		return flac_ip.output->output_time();
+}
+
+void FLAC_XMMS__cleanup()
+{
+    g_free(flac_ip.description);
+    flac_ip.description = NULL;
+
+    if (flac_cfg.title.tag_format) {
+        free(flac_cfg.title.tag_format);
+        flac_cfg.title.tag_format = NULL;
+    }
+
+    if (flac_cfg.title.user_char_set) {
+        free(flac_cfg.title.user_char_set);
+        flac_cfg.title.user_char_set = NULL;
+    }
+
+    if (flac_cfg.stream.proxy_host) {
+        free(flac_cfg.stream.proxy_host);
+        flac_cfg.stream.proxy_host = NULL;
+    }
+
+    if (flac_cfg.stream.proxy_user) {
+        free(flac_cfg.stream.proxy_user);
+        flac_cfg.stream.proxy_user = NULL;
+
+    }
+
+    if (flac_cfg.stream.proxy_pass) {
+        free(flac_cfg.stream.proxy_pass);
+        flac_cfg.stream.proxy_pass = NULL;
+    }
+
+	safe_decoder_delete_(decoder_);
+	decoder_ = 0;
+}
+
+void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
+{
+	FLAC__StreamMetadata streaminfo;
+
+	if(0 == filename)
+		filename = "";
+
+	if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) {
+		/* @@@ how to report the error? */
+		if(title) {
+			if (!is_http_source(filename)) {
+				static const char *errtitle = "Invalid FLAC File: ";
+				*title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1);
+				sprintf(*title, "%s\"%s\"", errtitle, filename);
+			} else {
+				*title = NULL;
+			}
+		}
+		if(length_in_msec)
+			*length_in_msec = -1;
+		return;
+	}
+
+	if(title) {
+		*title = flac_format_song_title(filename);
+	}
+	if(length_in_msec) {
+		FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5);
+		if (l > INT_MAX)
+			l = INT_MAX;
+		*length_in_msec = (int)l;
+	}
+}
+
+/***********************************************************************
+ * local routines
+ **********************************************************************/
+
+void *play_loop_(void *arg)
+{
+	unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1;
+	FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0;
+
+	(void)arg;
+
+	while(stream_data_.is_playing) {
+		if(!stream_data_.eof) {
+			while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) {
+				unsigned s;
+
+				s = sample_buffer_last_ - sample_buffer_first_;
+				if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) {
+					stream_data_.eof = true;
+					break;
+				}
+				else if(!FLAC__stream_decoder_process_single(decoder_)) {
+					/*@@@ this should probably be a dialog */
+					fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n");
+					stream_data_.eof = true;
+					break;
+				}
+				blocksize = sample_buffer_last_ - sample_buffer_first_ - s;
+				decode_position_frame_last = decode_position_frame;
+				if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+					decode_position_frame = 0;
+			}
+			if(sample_buffer_last_ - sample_buffer_first_ > 0) {
+				const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE);
+				int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+				FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample;
+				unsigned written_time, bh_index_w;
+				FLAC__uint64 decode_position;
+
+				sample_buffer_first_ += n;
+				while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+					xmms_usleep(10000);
+				if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1)
+					produce_audio(flac_ip.output->written_time(), stream_data_.sample_format,
+						stream_data_.channels, bytes, sample_buffer_start, NULL);
+
+				/* compute current bitrate */
+
+				written_time = flac_ip.output->written_time();
+				bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+				if(bh_index_w != bh_index_last_w) {
+					bh_index_last_w = bh_index_w;
+					decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize;
+					bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] =
+						decode_position > decode_position_last && written_time > written_time_last ?
+							8000 * (decode_position - decode_position_last) / (written_time - written_time_last) :
+							stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample;
+					decode_position_last = decode_position;
+					written_time_last = written_time;
+				}
+			}
+			else {
+				stream_data_.eof = true;
+				xmms_usleep(10000);
+			}
+		}
+		else
+			xmms_usleep(10000);
+		if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) {
+			const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec;
+			FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples);
+			if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples)
+				target_sample = stream_data_.total_samples - 1;
+			if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) {
+				flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000);
+				bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+				if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame))
+					decode_position_frame = 0;
+				stream_data_.eof = false;
+				sample_buffer_first_ = sample_buffer_last_ = 0;
+			}
+			else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) {
+				/*@@@ this should probably be a dialog */
+				fprintf(stderr, "libxmms-flac: SEEK ERROR\n");
+				FLAC__stream_decoder_flush(decoder_);
+				stream_data_.eof = false;
+				sample_buffer_first_ = sample_buffer_last_ = 0;
+			}
+			stream_data_.seek_to_in_sec = -1;
+		}
+		else {
+			/* display the right bitrate from history */
+			unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE;
+			if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) {
+				bh_index_last_o = bh_index_o;
+				flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels);
+			}
+		}
+	}
+
+	safe_decoder_finish_(decoder_);
+
+	/* are these two calls necessary? */
+	flac_ip.output->buffer_free();
+	flac_ip.output->buffer_free();
+
+	g_free(stream_data_.title);
+
+	g_thread_exit(NULL);
+	return 0; /* to silence the compiler warning about not returning a value */
+}
+
+FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder)
+{
+	if(decoder == 0)
+		return false;
+
+	safe_decoder_finish_(decoder);
+
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	if(stream_data_.is_http_source) {
+		flac_http_open(filename, 0);
+		if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return false;
+	}
+	else {
+		if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+			return false;
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		return false;
+
+	return true;
+}
+
+void safe_decoder_finish_(FLAC__StreamDecoder *decoder)
+{
+	if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED)
+		FLAC__stream_decoder_finish(decoder);
+	if(stream_data_.is_http_source)
+		flac_http_close();
+}
+
+void safe_decoder_delete_(FLAC__StreamDecoder *decoder)
+{
+	if(decoder) {
+		safe_decoder_finish_(decoder);
+		FLAC__stream_decoder_delete(decoder);
+	}
+}
+
+FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	(void)decoder;
+	(void)client_data;
+	*bytes = flac_http_read(buffer, *bytes);
+	return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize;
+	const unsigned bits_per_sample = stream_data->bits_per_sample;
+	FLAC__byte *sample_buffer_start;
+
+	(void)decoder;
+
+	if(stream_data->abort_flag)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+	if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) {
+		memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample);
+		sample_buffer_last_ -= sample_buffer_first_;
+		sample_buffer_first_ = 0;
+	}
+	sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample;
+	if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) {
+		FLAC__replaygain_synthesis__apply_gain(
+				sample_buffer_start,
+				!is_big_endian_host_,
+				stream_data->sample_format_bytes_per_sample == 1, /* unsigned_data_out */
+				buffer,
+				wide_samples,
+				channels,
+				bits_per_sample,
+				stream_data->sample_format_bytes_per_sample * 8,
+				stream_data->replay_scale,
+				flac_cfg.output.replaygain.hard_limit,
+				flac_cfg.output.resolution.replaygain.dither,
+				&stream_data->dither_context
+		);
+	}
+	else if(is_big_endian_host_) {
+		FLAC__plugin_common__pack_pcm_signed_big_endian(
+			sample_buffer_start,
+			buffer,
+			wide_samples,
+			channels,
+			bits_per_sample,
+			stream_data->sample_format_bytes_per_sample * 8
+		);
+	}
+	else {
+		FLAC__plugin_common__pack_pcm_signed_little_endian(
+			sample_buffer_start,
+			buffer,
+			wide_samples,
+			channels,
+			bits_per_sample,
+			stream_data->sample_format_bytes_per_sample * 8
+		);
+	}
+
+	sample_buffer_last_ += wide_samples;
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	(void)decoder;
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		stream_data->total_samples = metadata->data.stream_info.total_samples;
+		stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+		stream_data->channels = metadata->data.stream_info.channels;
+		stream_data->sample_rate = metadata->data.stream_info.sample_rate;
+		{
+			FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5);
+			if (l > INT_MAX)
+				l = INT_MAX;
+			stream_data->length_in_msec = (int)l;
+		}
+	}
+	else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+		double reference, gain, peak;
+		if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) {
+			stream_data->has_replaygain = true;
+			stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit);
+		}
+	}
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	stream_data_struct *stream_data = (stream_data_struct *)client_data;
+	(void)decoder;
+	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+		stream_data->abort_flag = true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,24 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__PLUGIN_XMMS__PLUGIN_H
+#define FLAC__PLUGIN_XMMS__PLUGIN_H
+
+void set_track_info(const char* title, int length_in_msec);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/Makefile	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,28 @@
+include ../../../mk/rules.mk
+include ../../../mk/init.mk
+
+CFLAGS += $(PICFLAGS) -I.. -I../../..
+
+OBJECTIVE_LIBS_NOINST = libplugin_common.a
+
+noinst_HEADERS = \
+	all.h \
+	charset.h \
+	defs.h \
+	dither.h \
+	locale_hack.h \
+	tags.h \
+	replaygain.h
+
+SOURCES = \
+	charset.c \
+	dither.c \
+	tags.c \
+	replaygain.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+libplugin_common.a: $(OBJECTS)
+	$(AR) cq $@ $(OBJECTS)
+
+include ../../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/all.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,27 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__ALL_H
+#define FLAC__PLUGIN_COMMON__ALL_H
+
+#include "charset.h"
+#include "dither.h"
+#include "locale_hack.h"
+#include "tags.h"
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/charset.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,156 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * Only slightly modified charset.c from:
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  Håvard Kvålen <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "charset.h"
+
+
+/*************
+ * Functions *
+ *************/
+
+char* FLAC_plugin__charset_get_current (void)
+{
+	char *charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+	if (!charset)
+		charset = nl_langinfo(CODESET);
+#endif
+
+    if (charset)
+        return strdup(charset);
+
+    return strdup("ISO-8859-1");
+}
+
+
+#ifdef HAVE_ICONV
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+	size_t outleft, outsize, length;
+	iconv_t cd;
+	char *out, *outptr;
+	const char *input = string;
+
+	if (!string)
+		return NULL;
+
+	length = strlen(string);
+
+	if ((cd = iconv_open(to, from)) == (iconv_t)-1)
+	{
+#ifdef DEBUG
+		fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to);
+#endif
+		return strdup(string);
+	}
+
+	/* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */
+	/* + 1 for nul in case len == 1 */
+	outsize = ((length + 3) & ~3) + 1;
+	out = (char*)malloc(outsize);
+	outleft = outsize - 1;
+	outptr = out;
+
+retry:
+#if defined __OpenBSD__ || defined __NetBSD__
+	if (iconv(cd, &input, &length, &outptr, &outleft) == (size_t)-1)
+#else
+	if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)-1)
+#endif
+	{
+		int used;
+		switch (errno)
+		{
+			case E2BIG:
+				used = outptr - out;
+				outsize = (outsize - 1) * 2 + 1;
+				out = realloc(out, outsize);
+				outptr = out + used;
+				outleft = outsize - 1 - used;
+				goto retry;
+			case EINVAL:
+				break;
+			case EILSEQ:
+				/* Invalid sequence, try to get the rest of the string */
+				input++;
+				length = strlen(input);
+				goto retry;
+			default:
+#ifdef DEBUG
+				fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno));
+#endif
+				break;
+		}
+	}
+	*outptr = '\0';
+
+	iconv_close(cd);
+	return out;
+}
+#else
+char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to)
+{
+	(void)from, (void)to;
+	if (!string)
+		return NULL;
+	return strdup(string);
+}
+#endif
+
+#ifdef HAVE_ICONV
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+	iconv_t cd;
+
+	if ((cd=iconv_open(to,from)) == (iconv_t)-1)
+	{
+		/* Conversion not supported */
+		return 0;
+	}
+	iconv_close(cd);
+	return 1;
+}
+#else
+int FLAC_plugin__charset_test_conversion (char *from, char *to)
+{
+	(void)from, (void)to;
+	return 1;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/charset.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,39 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * Only slightly modified charset.h from:
+ * charset.h - 2001/12/04
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef FLAC__PLUGIN_COMMON__CHARSET_H
+#define FLAC__PLUGIN_COMMON__CHARSET_H
+
+
+/**************
+ * Prototypes *
+ **************/
+
+char *FLAC_plugin__charset_get_current();
+char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to);
+
+/* returns 1 for success, 0 for failure or no iconv */
+int FLAC_plugin__charset_test_conversion(char *from, char *to);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/defs.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,24 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DEFS_H
+#define FLAC__PLUGIN_COMMON__DEFS_H
+
+#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/dither.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,260 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * dithering routine derived from (other GPLed source):
+ * mad - MPEG audio decoder
+ * Copyright (C) 2000-2001 Robert Leslie
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "dither.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+
+#if defined _MSC_VER
+#define FLAC__INLINE __inline
+#else
+#define FLAC__INLINE
+#endif
+
+/* 32-bit pseudo-random number generator
+ *
+ * @@@ According to Miroslav, this one is poor quality, the one from the
+ * @@@ original replaygain code is much better
+ */
+static FLAC__INLINE FLAC__uint32 prng(FLAC__uint32 state)
+{
+	return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
+}
+
+/* dither routine derived from MAD winamp plugin */
+
+typedef struct {
+	FLAC__int32 error[3];
+	FLAC__int32 random;
+} dither_state;
+
+static FLAC__INLINE FLAC__int32 linear_dither(unsigned source_bps, unsigned target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX)
+{
+	unsigned scalebits;
+	FLAC__int32 output, mask, random;
+
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+
+	/* noise shape */
+	sample += dither->error[0] - dither->error[1] + dither->error[2];
+
+	dither->error[2] = dither->error[1];
+	dither->error[1] = dither->error[0] / 2;
+
+	/* bias */
+	output = sample + (1L << (source_bps - target_bps - 1));
+
+	scalebits = source_bps - target_bps;
+	mask = (1L << scalebits) - 1;
+
+	/* dither */
+	random = (FLAC__int32)prng(dither->random);
+	output += (random & mask) - (dither->random & mask);
+
+	dither->random = random;
+
+	/* clip */
+	if(output > MAX) {
+		output = MAX;
+
+		if(sample > MAX)
+			sample = MAX;
+	}
+	else if(output < MIN) {
+		output = MIN;
+
+		if(sample < MIN)
+			sample = MIN;
+	}
+
+	/* quantize */
+	output &= ~mask;
+
+	/* error feedback */
+	dither->error[0] = sample - output;
+
+	/* scale */
+	return output >> scalebits;
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
+{
+	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+	FLAC__byte * const start = data;
+	FLAC__int32 sample;
+	const FLAC__int32 *input_;
+	unsigned samples, channel;
+	const unsigned bytes_per_sample = target_bps / 8;
+	const unsigned incr = bytes_per_sample * channels;
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+	FLAC__ASSERT((source_bps & 7) == 0);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	if(source_bps != target_bps) {
+		const FLAC__int32 MIN = -(1L << (source_bps - 1));
+		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+		for(channel = 0; channel < channels; channel++) {
+			
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 16:
+						data[0] = (FLAC__byte)(sample >> 8);
+						data[1] = (FLAC__byte)sample;
+						break;
+					case 24:
+						data[0] = (FLAC__byte)(sample >> 16);
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[2] = (FLAC__byte)sample;
+						break;
+				}
+
+				data += incr;
+			}
+		}
+	}
+	else {
+		for(channel = 0; channel < channels; channel++) {
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = *input_++;
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 16:
+						data[0] = (FLAC__byte)(sample >> 8);
+						data[1] = (FLAC__byte)sample;
+						break;
+					case 24:
+						data[0] = (FLAC__byte)(sample >> 16);
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[2] = (FLAC__byte)sample;
+						break;
+				}
+
+				data += incr;
+			}
+		}
+	}
+
+	return wide_samples * channels * (target_bps/8);
+}
+
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps)
+{
+	static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS];
+	FLAC__byte * const start = data;
+	FLAC__int32 sample;
+	const FLAC__int32 *input_;
+	unsigned samples, channel;
+	const unsigned bytes_per_sample = target_bps / 8;
+	const unsigned incr = bytes_per_sample * channels;
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps < 32);
+	FLAC__ASSERT(target_bps <= 24);
+	FLAC__ASSERT(target_bps <= source_bps);
+	FLAC__ASSERT((source_bps & 7) == 0);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	if(source_bps != target_bps) {
+		const FLAC__int32 MIN = -(1L << (source_bps - 1));
+		const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */
+
+		for(channel = 0; channel < channels; channel++) {
+			
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX);
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 24:
+						data[2] = (FLAC__byte)(sample >> 16);
+						/* fall through */
+					case 16:
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[0] = (FLAC__byte)sample;
+				}
+
+				data += incr;
+			}
+		}
+	}
+	else {
+		for(channel = 0; channel < channels; channel++) {
+			samples = wide_samples;
+			data = start + bytes_per_sample * channel;
+			input_ = input[channel];
+
+			while(samples--) {
+				sample = *input_++;
+
+				switch(target_bps) {
+					case 8:
+						data[0] = sample ^ 0x80;
+						break;
+					case 24:
+						data[2] = (FLAC__byte)(sample >> 16);
+						/* fall through */
+					case 16:
+						data[1] = (FLAC__byte)(sample >> 8);
+						data[0] = (FLAC__byte)sample;
+				}
+
+				data += incr;
+			}
+		}
+	}
+
+	return wide_samples * channels * (target_bps/8);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/dither.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,29 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__DITHER_H
+#define FLAC__PLUGIN_COMMON__DITHER_H
+
+#include <stdlib.h> /* for size_t */
+#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */
+#include "FLAC/ordinals.h"
+
+size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
+size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/locale_hack.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,55 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * Based on:
+ * locale.h - 2000/05/05 13:10 Jerome Couderc
+ *  EasyTAG - Tag editor for MP3 and OGG files
+ *  Copyright (C) 1999-2001  H蛆ard Kv虱en <havardk@xmms.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+/*
+ * Gettext support for EasyTAG
+ */
+
+
+#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H
+
+#include <locale.h>
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+#  include <libintl.h>
+#  define _(String) gettext (String)
+#  ifdef gettext_noop
+#    define N_(String) gettext_noop (String)
+#  else
+#    define N_(String) (String)
+#  endif
+#else
+#  define textdomain(String) (String)
+#  define gettext(String) (String)
+#  define dgettext(Domain,Message) (Message)
+#  define dcgettext(Domain,Message,Type) (Message)
+#  define bindtextdomain(Domain,Directory) (Domain)
+#  define _(String) (String)
+#  define N_(String) (String)
+#endif
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/replaygain.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,62 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "replaygain.h"
+#include "FLAC/ordinals.h"
+#include "FLAC/metadata.h"
+#include "grabbag.h"
+
+void FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set)
+{
+	FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
+
+	*track_gain_set = *album_gain_set = *track_peak_set = *album_peak_set = false;
+
+	if(0 != iterator) {
+		if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+			FLAC__bool got_vorbis_comments = false;
+			do {
+				if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+					FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
+					if(0 != block) {
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/false, /*strict=*/true, reference, track_gain, track_peak)) {
+							*reference_set = *track_gain_set = *track_peak_set = true;
+						}
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/true, /*strict=*/true, reference, album_gain, album_peak)) {
+							*reference_set = *album_gain_set = *album_peak_set = true;
+						}
+						FLAC__metadata_object_delete(block);
+						got_vorbis_comments = true;
+					}
+				}
+			} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
+		}
+		FLAC__metadata_simple_iterator_delete(iterator);
+	}
+	return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/replaygain.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,32 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+#define FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+
+#include "FLAC/ordinals.h"
+
+void FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/tags.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,307 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tags.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+
+
+static __inline unsigned local__wide_strlen(const FLAC__uint16 *s)
+{
+	unsigned n = 0;
+	while(*s++)
+		n++;
+	return n;
+}
+
+static __inline unsigned local__utf8len(const FLAC__byte *utf8)
+{
+	FLAC__ASSERT(0 != utf8);
+	if ((utf8[0] & 0x80) == 0)
+		return 1;
+	else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80)
+		return 2;
+	else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80)
+		return 3;
+	else
+		return 0;
+}
+
+static __inline unsigned local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2)
+{
+	const unsigned len = local__utf8len(utf8);
+
+	FLAC__ASSERT(0 != ucs2);
+
+	if (len == 1)
+		*ucs2 = *utf8;
+	else if (len == 2)
+		*ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F);
+	else if (len == 3)
+		*ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F);
+
+	return len;
+}
+
+static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, unsigned length)
+{
+	FLAC__uint16 *out;
+	unsigned chars = 0;
+
+	FLAC__ASSERT(0 != src);
+
+	/* calculate length */
+	{
+		const char *s, *end;
+		for (s=src, end=src+length; s<end; chars++) {
+			const unsigned n = local__utf8len((unsigned char*)s);
+			if (n == 0)
+				return 0;
+			s += n;
+		}
+		FLAC__ASSERT(s == end);
+	}
+
+	/* allocate */
+	out = (FLAC__uint16*)malloc(chars * sizeof(FLAC__uint16));
+	if (0 == out) {
+		FLAC__ASSERT(0);
+		return 0;
+	}
+
+	/* convert */
+	{
+		FLAC__uint16 *u = out;
+		for ( ; chars; chars--)
+			src += local__utf8_to_ucs2((const unsigned char*)src, u++);
+	}
+
+	return out;
+}
+
+static __inline unsigned local__ucs2len(FLAC__uint16 ucs2)
+{
+	if (ucs2 < 0x0080)
+		return 1;
+	else if (ucs2 < 0x0800)
+		return 2;
+	else
+		return 3;
+}
+
+static __inline unsigned local__ucs2_to_utf8(FLAC__uint16 ucs2, FLAC__byte *utf8)
+{
+	if (ucs2 < 0x080) {
+		utf8[0] = (FLAC__byte)ucs2;
+		return 1;
+	}
+	else if (ucs2 < 0x800) {
+		utf8[0] = 0xc0 | (ucs2 >> 6);
+		utf8[1] = 0x80 | (ucs2 & 0x3f);
+		return 2;
+	}
+	else {
+		utf8[0] = 0xe0 | (ucs2 >> 12);
+		utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f);
+		utf8[2] = 0x80 | (ucs2 & 0x3f);
+		return 3;
+	}
+}
+
+static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, unsigned length)
+{
+	char *out;
+	unsigned len = 0;
+
+	FLAC__ASSERT(0 != src);
+
+	/* calculate length */
+	{
+		unsigned i;
+		for (i = 0; i < length; i++)
+			len += local__ucs2len(src[i]);
+	}
+
+	/* allocate */
+	out = (char*)malloc(len * sizeof(char));
+	if (0 == out)
+		return 0;
+
+	/* convert */
+	{
+		unsigned char *u = (unsigned char*) out;
+		for ( ; *src; src++)
+			u += local__ucs2_to_utf8(*src, u);
+		local__ucs2_to_utf8(*src, u);
+	}
+
+	return out;
+}
+
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags)
+{
+	if(!FLAC__metadata_get_tags(filename, tags))
+		if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)))
+			return false;
+	return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__Metadata_Iterator *iterator;
+	FLAC__StreamMetadata *block;
+	FLAC__bool got_vorbis_comments = false;
+	FLAC__bool ok;
+
+	if(0 == (chain = FLAC__metadata_chain_new()))
+		return false;
+
+	if(!FLAC__metadata_chain_read(chain, filename)) {
+		FLAC__metadata_chain_delete(chain);
+		return false;
+	}
+
+	if(0 == (iterator = FLAC__metadata_iterator_new())) {
+		FLAC__metadata_chain_delete(chain);
+		return false;
+	}
+
+	FLAC__metadata_iterator_init(iterator, chain);
+
+	do {
+		if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+			got_vorbis_comments = true;
+	} while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator));
+
+	if(0 == (block = FLAC__metadata_object_clone(tags))) {
+		FLAC__metadata_chain_delete(chain);
+		FLAC__metadata_iterator_delete(iterator);
+		return false;
+	}
+
+	if(got_vorbis_comments)
+		ok = FLAC__metadata_iterator_set_block(iterator, block);
+	else
+		ok = FLAC__metadata_iterator_insert_block_after(iterator, block);
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	if(ok) {
+		FLAC__metadata_chain_sort_padding(chain);
+		ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true);
+	}
+
+	FLAC__metadata_chain_delete(chain);
+
+	return ok;
+}
+
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags)
+{
+	FLAC__metadata_object_delete(*tags);
+	*tags = 0;
+}
+
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name)
+{
+	const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name);
+	return (i < 0? 0 : strchr((const char*)tags->data.vorbis_comment.comments[i].entry, '=')+1);
+}
+
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name)
+{
+	const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+	if(0 == utf8)
+		return 0;
+	return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */
+}
+
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name)
+{
+	return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name);
+}
+
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags)
+{
+	int n = (int)tags->data.vorbis_comment.num_comments;
+	if(n > 0) {
+		if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0))
+			n = -1;
+	}
+	return n;
+}
+
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator)
+{
+	int i;
+
+	FLAC__ASSERT(0 != tags);
+	FLAC__ASSERT(0 != name);
+	FLAC__ASSERT(0 != value);
+
+	if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) {
+		FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i;
+		const size_t value_len = strlen(value);
+		const size_t separator_len = strlen(separator);
+		FLAC__byte *new_entry;
+		if(0 == (new_entry = (FLAC__byte*)realloc(entry->entry, entry->length + value_len + separator_len + 1)))
+			return false;
+		memcpy(new_entry+entry->length, separator, separator_len);
+		entry->length += separator_len;
+		memcpy(new_entry+entry->length, value, value_len);
+		entry->length += value_len;
+		new_entry[entry->length] = '\0';
+		entry->entry = new_entry;
+	}
+	else {
+		FLAC__StreamMetadata_VorbisComment_Entry entry;
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value))
+			return false;
+		FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false);
+	}
+	return true;
+}
+
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+	FLAC__ASSERT(0 != tags);
+	FLAC__ASSERT(0 != name);
+	FLAC__ASSERT(0 != value);
+
+	{
+		char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */
+		if(0 == utf8)
+			return false;
+		if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) {
+			free(utf8);
+			return false;
+		}
+		free(utf8);
+	}
+	if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false))
+		return false;
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/plugin_common/tags.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,74 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__TAGS_H
+#define FLAC__PLUGIN_COMMON__TAGS_H
+
+#include "FLAC/format.h"
+
+FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags);
+FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags);
+
+/*
+ * Deletes the tags object and sets '*tags' to NULL.
+ */
+void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags);
+
+/*
+ * Gets the value (in UTF-8) of the first tag with the given name (NULL if no
+ * such tag exists).
+ */
+const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Gets the value (in UCS-2) of the first tag with the given name (NULL if no
+ * such tag exists).
+ *
+ * NOTE: the returned string is malloc()ed and must be free()d by the caller.
+ */
+FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags with the given 'name'.  Returns the number of tags removed,
+ * or -1 on memory allocation error.
+ */
+int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name);
+
+/*
+ * Removes all tags.  Returns the number of tags removed, or -1 on memory
+ * allocation error.
+ */
+int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UTF-8.  If
+ * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the
+ * first such tag's value is appended with separator, then value.
+ */
+FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator);
+
+/*
+ * Adds a "name=value" tag to the tags.  'value' must be in UCS-2.  If 'tags'
+ * already contains a tag or tags for 'name', then they will be replaced
+ * according to 'replace_all': if 'replace_all' is false, only the first such
+ * tag will be replaced; if true, all matching tags will be replaced by the one
+ * new tag. 
+ */
+FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/replaygain.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,665 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "grabbag.h"
+#include "replaygain_analysis.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for chmod() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#ifdef local_min
+#undef local_min
+#endif
+#define local_min(a,b) ((a)<(b)?(a):(b))
+
+#ifdef local_max
+#undef local_max
+#endif
+#define local_max(a,b) ((a)>(b)?(a):(b))
+
+static const char *reference_format_ = "%s=%2.1f dB";
+static const char *gain_format_ = "%s=%+2.2f dB";
+static const char *peak_format_ = "%s=%1.8f";
+
+static double album_peak_, title_peak_;
+
+const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
+/*
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
+*/
+
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
+
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+	return (0 == stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct stat *stats)
+{
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != stats);
+
+	(void)chmod(filename, stats->st_mode);
+}
+
+static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value)
+{
+	char buffer[256];
+	char *saved_locale;
+	FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != format);
+	FLAC__ASSERT(0 != name);
+
+	buffer[sizeof(buffer)-1] = '\0';
+	/*
+	 * We need to save the old locale and switch to "C" because the locale
+	 * influences the formatting of %f and we want it a certain way.
+	 */
+	saved_locale = setlocale(LC_ALL, 0);
+	setlocale(LC_ALL, "C");
+#if defined _MSC_VER || defined __MINGW32__
+	_snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#else
+	snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#endif
+	setlocale(LC_ALL, saved_locale);
+
+	entry.entry = (FLAC__byte *)buffer;
+	entry.length = strlen(buffer);
+
+	return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
+}
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency)
+{
+	static const unsigned valid_sample_rates[] = {
+		8000,
+		11025,
+		12000,
+		16000,
+		22050,
+		24000,
+		32000,
+		44100,
+		48000
+	};
+	static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]);
+
+	unsigned i;
+
+	for(i = 0; i < n_valid_sample_rates; i++)
+		if(sample_frequency == valid_sample_rates[i])
+			return true;
+	return false;
+}
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency)
+{
+	title_peak_ = album_peak_ = 0.0;
+	return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK;
+}
+
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples)
+{
+	/* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
+	static Float_t lbuffer[2048], rbuffer[2048];
+	static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
+	FLAC__int32 block_peak = 0, s;
+	unsigned i, j;
+
+	FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE);
+	FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4);
+	/*
+	 * We use abs() on a FLAC__int32 which is undefined for the most negative value.
+	 * If the reference codec ever handles 32bps we will have to write a special
+	 * case here.
+	 */
+	FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32);
+
+	if(bps == 16) {
+		if(is_stereo) {
+			j = 0;
+			while(samples > 0) {
+				const unsigned n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (Float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+
+					s = input[1][j];
+					rbuffer[i] = (Float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+		else {
+			j = 0;
+			while(samples > 0) {
+				const unsigned n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (Float_t)s;
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+	}
+	else { /* bps must be < 32 according to above assertion */
+		const double scale = (
+			(bps > 16)?
+				(double)1. / (double)(1u << (bps - 16)) :
+				(double)(1u << (16 - bps))
+		);
+
+		if(is_stereo) {
+			j = 0;
+			while(samples > 0) {
+				const unsigned n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (Float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+
+					s = input[1][j];
+					rbuffer[i] = (Float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+		else {
+			j = 0;
+			while(samples > 0) {
+				const unsigned n = local_min(samples, nbuffer);
+				for(i = 0; i < n; i++, j++) {
+					s = input[0][j];
+					lbuffer[i] = (Float_t)(scale * (double)s);
+					s = abs(s);
+					block_peak = local_max(block_peak, s);
+				}
+				samples -= n;
+				if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+					return false;
+			}
+		}
+	}
+
+	{
+		const double peak_scale = (double)(1u << (bps - 1));
+		double peak = (double)block_peak / peak_scale;
+		if(peak > title_peak_)
+			title_peak_ = peak;
+		if(peak > album_peak_)
+			album_peak_ = peak;
+	}
+
+	return true;
+}
+
+void grabbag__replaygain_get_album(float *gain, float *peak)
+{
+	*gain = (float)GetAlbumGain();
+	*peak = (float)album_peak_;
+	album_peak_ = 0.0;
+}
+
+void grabbag__replaygain_get_title(float *gain, float *peak)
+{
+	*gain = (float)GetTitleGain();
+	*peak = (float)title_peak_;
+	title_peak_ = 0.0;
+}
+
+
+typedef struct {
+	unsigned channels;
+	unsigned bits_per_sample;
+	unsigned sample_rate;
+	FLAC__bool error;
+} DecoderInstance;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+	const unsigned bits_per_sample = frame->header.bits_per_sample;
+	const unsigned channels = frame->header.channels;
+	const unsigned sample_rate = frame->header.sample_rate;
+	const unsigned samples = frame->header.blocksize;
+
+	(void)decoder;
+
+	if(
+		!instance->error &&
+		(channels == 2 || channels == 1) &&
+		bits_per_sample == instance->bits_per_sample &&
+		channels == instance->channels &&
+		sample_rate == instance->sample_rate
+	) {
+		instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples);
+	}
+	else {
+		instance->error = true;
+	}
+
+	if(!instance->error)
+		return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+	else
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+
+	(void)decoder;
+
+	if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		instance->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+		instance->channels = metadata->data.stream_info.channels;
+		instance->sample_rate = metadata->data.stream_info.sample_rate;
+
+		if(instance->channels != 1 && instance->channels != 2) {
+			instance->error = true;
+			return;
+		}
+
+		if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) {
+			instance->error = true;
+			return;
+		}
+	}
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	DecoderInstance *instance = (DecoderInstance*)client_data;
+
+	(void)decoder, (void)status;
+
+	instance->error = true;
+}
+
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
+{
+	DecoderInstance instance;
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+
+	if(0 == decoder)
+		return "memory allocation error";
+
+	instance.error = false;
+
+	/* It does these three by default but lets be explicit: */
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		return "initializing decoder";
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
+		FLAC__stream_decoder_delete(decoder);
+		return "decoding file";
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+
+	grabbag__replaygain_get_title(title_gain, title_peak);
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak)
+{
+	const char *error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
+		return "memory allocation error";
+
+	if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
+		return "memory allocation error";
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
+	)
+		return "memory allocation error";
+
+	if(
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
+	)
+		return "memory allocation error";
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
+	)
+		return "memory allocation error";
+
+	if(
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
+	)
+		return "memory allocation error";
+
+	return 0;
+}
+
+static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block)
+{
+	FLAC__Metadata_Iterator *iterator;
+	const char *error;
+	FLAC__bool found_vc_block = false;
+
+	if(0 == (*chain = FLAC__metadata_chain_new()))
+		return "memory allocation error";
+
+	if(!FLAC__metadata_chain_read(*chain, filename)) {
+		error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+		FLAC__metadata_chain_delete(*chain);
+		return error;
+	}
+
+	if(0 == (iterator = FLAC__metadata_iterator_new())) {
+		FLAC__metadata_chain_delete(*chain);
+		return "memory allocation error";
+	}
+
+	FLAC__metadata_iterator_init(iterator, *chain);
+
+	do {
+		*block = FLAC__metadata_iterator_get_block(iterator);
+		if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+			found_vc_block = true;
+	} while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+	if(!found_vc_block) {
+		/* create a new block */
+		*block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+		if(0 == *block) {
+			FLAC__metadata_chain_delete(*chain);
+			FLAC__metadata_iterator_delete(iterator);
+			return "memory allocation error";
+		}
+		while(FLAC__metadata_iterator_next(iterator))
+			;
+		if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) {
+			error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+			FLAC__metadata_chain_delete(*chain);
+			FLAC__metadata_iterator_delete(iterator);
+			return error;
+		}
+		/* iterator is left pointing to new block */
+		FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block);
+	}
+
+	FLAC__metadata_iterator_delete(iterator);
+
+	FLAC__ASSERT(0 != *block);
+	FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	return 0;
+}
+
+static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime)
+{
+	struct stat stats;
+	const FLAC__bool have_stats = get_file_stats_(filename, &stats);
+
+	(void)grabbag__file_change_stats(filename, /*read_only=*/false);
+
+	FLAC__metadata_chain_sort_padding(chain);
+	if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) {
+		FLAC__metadata_chain_delete(chain);
+		return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
+	}
+
+	FLAC__metadata_chain_delete(chain);
+
+	if(have_stats)
+		set_file_stats_(filename, &stats);
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
+static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val)
+{
+	char s[32], *end;
+	const char *p, *q;
+	double v;
+
+	FLAC__ASSERT(0 != entry);
+	FLAC__ASSERT(0 != val);
+
+	p = (const char *)entry->entry;
+	q = strchr(p, '=');
+	if(0 == q)
+		return false;
+	q++;
+	memset(s, 0, sizeof(s)-1);
+	strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p)));
+
+	v = strtod(s, &end);
+	if(end == s)
+		return false;
+
+	*val = v;
+	return true;
+}
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
+{
+	int reference_offset, gain_offset, peak_offset;
+
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(0 != reference);
+	FLAC__ASSERT(0 != gain);
+	FLAC__ASSERT(0 != peak);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	/* Default to current level until overridden by a detected tag; this
+	 * will always be true until we change replaygain_analysis.c
+	 */
+	*reference = ReplayGainReferenceLoudness;
+
+	if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
+		(void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
+
+	if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+	if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+	if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+	if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+	return true;
+}
+
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping)
+{
+	double scale;
+	FLAC__ASSERT(peak >= 0.0);
+ 	gain += preamp;
+	scale = (float) pow(10.0, gain * 0.05);
+	if(prevent_clipping && peak > 0.0) {
+		const double max_scale = (float)(1.0 / peak);
+		if(scale > max_scale)
+			scale = max_scale;
+	}
+	return scale;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/replaygain_analysis.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,419 @@
+/*
+ *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ *  Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  concept and filter values by David Robinson (David@Robinson.org)
+ *    -- blame him if you think the idea is flawed
+ *  original coding by Glen Sawyer (glensawyer@hotmail.com)
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *
+ *  lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
+ *    -- credit him for all the _good_ programming ;)
+ *
+ *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ *
+ *  For an explanation of the concepts and the basic algorithms involved, go to:
+ *    http://www.replaygain.org/
+ */
+
+/*
+ *  Here's the deal. Call
+ *
+ *    InitGainAnalysis ( long samplefreq );
+ *
+ *  to initialize everything. Call
+ *
+ *    AnalyzeSamples ( const Float_t*  left_samples,
+ *                     const Float_t*  right_samples,
+ *                     size_t          num_samples,
+ *                     int             num_channels );
+ *
+ *  as many times as you want, with as many or as few samples as you want.
+ *  If mono, pass the sample buffer in through left_samples, leave
+ *  right_samples NULL, and make sure num_channels = 1.
+ *
+ *    GetTitleGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
+ *
+ *    GetAlbumGain()
+ *
+ *  will return the recommended dB level change for all samples analyzed
+ *  since InitGainAnalysis() was called and finalized with GetTitleGain().
+ *
+ *  Pseudo-code to process an album:
+ *
+ *    Float_t       l_samples [4096];
+ *    Float_t       r_samples [4096];
+ *    size_t        num_samples;
+ *    unsigned int  num_songs;
+ *    unsigned int  i;
+ *
+ *    InitGainAnalysis ( 44100 );
+ *    for ( i = 1; i <= num_songs; i++ ) {
+ *        while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
+ *            AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
+ *        fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
+ *    }
+ *    fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
+ */
+
+/*
+ *  So here's the main source of potential code confusion:
+ *
+ *  The filters applied to the incoming samples are IIR filters,
+ *  meaning they rely on up to <filter order> number of previous samples
+ *  AND up to <filter order> number of previous filtered samples.
+ *
+ *  I set up the AnalyzeSamples routine to minimize memory usage and interface
+ *  complexity. The speed isn't compromised too much (I don't think), but the
+ *  internal complexity is higher than it should be for such a relatively
+ *  simple routine.
+ *
+ *  Optimization/clarity suggestions are welcome.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "replaygain_analysis.h"
+
+Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
+
+typedef unsigned short  Uint16_t;
+typedef signed short    Int16_t;
+typedef unsigned int    Uint32_t;
+typedef signed int      Int32_t;
+
+#define YULE_ORDER         10
+#define BUTTER_ORDER        2
+#define RMS_PERCENTILE      0.95        /* percentile which is louder than the proposed level */
+#define MAX_SAMP_FREQ   48000.          /* maximum allowed sample frequency [Hz] */
+#define RMS_WINDOW_TIME     0.050       /* Time slice size [s] */
+#define STEPS_per_dB      100.          /* Table entries per dB */
+#define MAX_dB            120.          /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
+
+#define MAX_ORDER               (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
+/* [JEC] the following was originally #defined as:
+ *   (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME)
+ * but that seemed to fail to take into account the ceil() part of the
+ * sampleWindow calculation in ResetSampleFrequency(), and was causing
+ * buffer overflows for 48kHz analysis, hence the +1.
+ */
+#define MAX_SAMPLES_PER_WINDOW  (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.)   /* max. Samples per Time slice */
+#define PINK_REF                64.82 /* 298640883795 */                          /* calibration value */
+
+static Float_t          linprebuf [MAX_ORDER * 2];
+static Float_t*         linpre;                                          /* left input samples, with pre-buffer */
+static Float_t          lstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         lstep;                                           /* left "first step" (i.e. post first filter) samples */
+static Float_t          loutbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         lout;                                            /* left "out" (i.e. post second filter) samples */
+static Float_t          rinprebuf [MAX_ORDER * 2];
+static Float_t*         rinpre;                                          /* right input samples ... */
+static Float_t          rstepbuf  [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         rstep;
+static Float_t          routbuf   [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t*         rout;
+static unsigned int              sampleWindow;                           /* number of samples required to reach number of milliseconds required for RMS window */
+static unsigned long    totsamp;
+static double           lsum;
+static double           rsum;
+static int              freqindex;
+static Uint32_t  A [(size_t)(STEPS_per_dB * MAX_dB)];
+static Uint32_t  B [(size_t)(STEPS_per_dB * MAX_dB)];
+
+/* for each filter:
+   [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */
+
+#ifdef WIN32
+#pragma warning ( disable : 4305 )
+#endif
+
+static const Float_t  AYule [9] [11] = {
+    { 1., -3.84664617118067,  7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294,  9.48293806319790, -5.87257861775999,  2.75465861874613, -0.86984376593551, 0.13919314567432 },
+    { 1., -3.47845948550071,  6.36317777566148, -8.54751527471874,  9.47693607801280, -8.81498681370155,  6.85401540936998, -4.39470996079559,  2.19611684890774, -0.75104302451432, 0.13149317958808 },
+    { 1., -2.37898834973084,  2.84868151156327, -2.64577170229825,  2.23697657451713, -1.67148153367602,  1.00595954808547, -0.45953458054983,  0.16378164858596, -0.05032077717131, 0.02347897407020 },
+    { 1., -1.61273165137247,  1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906,  0.39120800788284, -0.22138138954925,  0.04500235387352,  0.02005851806501, 0.00302439095741 },
+    { 1., -1.49858979367799,  0.87350271418188,  0.12205022308084, -0.80774944671438,  0.47854794562326, -0.12453458140019, -0.04067510197014,  0.08333755284107, -0.04237348025746, 0.02977207319925 },
+    { 1., -0.62820619233671,  0.29661783706366, -0.37256372942400,  0.00213767857124, -0.42029820170918,  0.22199650564824,  0.00613424350682,  0.06747620744683,  0.05784820375801, 0.03222754072173 },
+    { 1., -1.04800335126349,  0.29156311971249, -0.26806001042947,  0.00819999645858,  0.45054734505008, -0.33032403314006,  0.06739368333110, -0.04784254229033,  0.01639907836189, 0.01807364323573 },
+    { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477,  0.14728154134330,  0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053,  0.02442357316099, 0.01818801111503 },
+    { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242,  0.26408300200955,  0.15113130533216, -0.17556493366449, -0.18823009262115,  0.05477720428674, 0.04704409688120 }
+};
+
+static const Float_t  BYule [9] [11] = {
+    { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619,  0.02161526843274, -0.02074045215285,  0.00594298065125,  0.00306428023191,  0.00012025322027,  0.00288463683916 },
+    { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936,  0.02245293253339, -0.02596338512915,  0.01624864962975, -0.00240879051584,  0.00674613682247, -0.00187763777362 },
+    { 0.15457299681924, -0.09331049056315, -0.06247880153653,  0.02163541888798, -0.05588393329856,  0.04781476674921,  0.00222312597743,  0.03174092540049, -0.01390589421898,  0.00651420667831, -0.00881362733839 },
+    { 0.30296907319327, -0.22613988682123, -0.08587323730772,  0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913,  0.06276101321749, -0.00000828086748,  0.00205861885564, -0.02950134983287 },
+    { 0.33642304856132, -0.25572241425570, -0.11828570177555,  0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440,  0.05724228140351,  0.00832043980773, -0.01635381384540, -0.01760176568150 },
+    { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551,  0.04078262797139, -0.12398163381748,  0.04097565135648,  0.10478503600251, -0.01863887810927, -0.03193428438915,  0.00541907748707 },
+    { 0.56619470757641, -0.75464456939302,  0.16242137742230,  0.16744243493672, -0.18901604199609,  0.30931782841830, -0.27562961986224,  0.00647310677246,  0.08647503780351, -0.03788984554840, -0.00588215443421 },
+    { 0.58100494960553, -0.53174909058578, -0.14289799034253,  0.17520704835522,  0.02377945217615,  0.15558449135573, -0.25344790059353,  0.01628462406333,  0.06920467763959, -0.03721611395801, -0.00749618797172 },
+    { 0.53648789255105, -0.42163034350696, -0.00275953611929,  0.04267842219415, -0.10214864179676,  0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000,  0.04788665548180, -0.02217936801134 }
+};
+
+static const Float_t  AButter [9] [3] = {
+    { 1., -1.97223372919527, 0.97261396931306 },
+    { 1., -1.96977855582618, 0.97022847566350 },
+    { 1., -1.95835380975398, 0.95920349965459 },
+    { 1., -1.95002759149878, 0.95124613669835 },
+    { 1., -1.94561023566527, 0.94705070426118 },
+    { 1., -1.92783286977036, 0.93034775234268 },
+    { 1., -1.91858953033784, 0.92177618768381 },
+    { 1., -1.91542108074780, 0.91885558323625 },
+    { 1., -1.88903307939452, 0.89487434461664 }
+};
+
+static const Float_t  BButter [9] [3] = {
+    { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
+    { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
+    { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
+    { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
+    { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
+    { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
+    { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
+    { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
+    { 0.94597685600279, -1.89195371200558, 0.94597685600279 }
+};
+
+#ifdef WIN32
+#pragma warning ( default : 4305 )
+#endif
+
+/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
+
+static void
+filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order )
+{
+    double  y;
+    size_t  i;
+    size_t  k;
+
+    for ( i = 0; i < nSamples; i++ ) {
+        y = input[i] * b[0];
+        for ( k = 1; k <= order; k++ )
+            y += input[i-k] * b[k] - output[i-k] * a[k];
+        output[i] = (Float_t)y;
+    }
+}
+
+/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
+
+int
+ResetSampleFrequency ( long samplefreq ) {
+    int  i;
+
+    /* zero out initial values */
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
+
+    switch ( (int)(samplefreq) ) {
+        case 48000: freqindex = 0; break;
+        case 44100: freqindex = 1; break;
+        case 32000: freqindex = 2; break;
+        case 24000: freqindex = 3; break;
+        case 22050: freqindex = 4; break;
+        case 16000: freqindex = 5; break;
+        case 12000: freqindex = 6; break;
+        case 11025: freqindex = 7; break;
+        case  8000: freqindex = 8; break;
+        default:    return INIT_GAIN_ANALYSIS_ERROR;
+    }
+
+    sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME);
+
+    lsum         = 0.;
+    rsum         = 0.;
+    totsamp      = 0;
+
+    memset ( A, 0, sizeof(A) );
+
+	return INIT_GAIN_ANALYSIS_OK;
+}
+
+int
+InitGainAnalysis ( long samplefreq )
+{
+	if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) {
+		return INIT_GAIN_ANALYSIS_ERROR;
+	}
+
+    linpre       = linprebuf + MAX_ORDER;
+    rinpre       = rinprebuf + MAX_ORDER;
+    lstep        = lstepbuf  + MAX_ORDER;
+    rstep        = rstepbuf  + MAX_ORDER;
+    lout         = loutbuf   + MAX_ORDER;
+    rout         = routbuf   + MAX_ORDER;
+
+    memset ( B, 0, sizeof(B) );
+
+    return INIT_GAIN_ANALYSIS_OK;
+}
+
+/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
+
+int
+AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels )
+{
+    const Float_t*  curleft;
+    const Float_t*  curright;
+    long            batchsamples;
+    long            cursamples;
+    long            cursamplepos;
+    int             i;
+
+    if ( num_samples == 0 )
+        return GAIN_ANALYSIS_OK;
+
+    cursamplepos = 0;
+    batchsamples = num_samples;
+
+    switch ( num_channels) {
+    case  1: right_samples = left_samples;
+    case  2: break;
+    default: return GAIN_ANALYSIS_ERROR;
+    }
+
+    if ( num_samples < MAX_ORDER ) {
+        memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) );
+        memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) );
+    }
+    else {
+        memcpy ( linprebuf + MAX_ORDER, left_samples,  MAX_ORDER   * sizeof(Float_t) );
+        memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER   * sizeof(Float_t) );
+    }
+
+    while ( batchsamples > 0 ) {
+        cursamples = batchsamples > (long)(sampleWindow-totsamp)  ?  (long)(sampleWindow - totsamp)  :  batchsamples;
+        if ( cursamplepos < MAX_ORDER ) {
+            curleft  = linpre+cursamplepos;
+            curright = rinpre+cursamplepos;
+            if (cursamples > MAX_ORDER - cursamplepos )
+                cursamples = MAX_ORDER - cursamplepos;
+        }
+        else {
+            curleft  = left_samples  + cursamplepos;
+            curright = right_samples + cursamplepos;
+        }
+
+        filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+        filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+
+        filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+        filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+
+        for ( i = 0; i < cursamples; i++ ) {             /* Get the squared values */
+            lsum += lout [totsamp+i] * lout [totsamp+i];
+            rsum += rout [totsamp+i] * rout [totsamp+i];
+        }
+
+        batchsamples -= cursamples;
+        cursamplepos += cursamples;
+        totsamp      += cursamples;
+        if ( totsamp == sampleWindow ) {  /* Get the Root Mean Square (RMS) for this set of samples */
+            double  val  = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 );
+            int     ival = (int) val;
+            if ( ival <                     0 ) ival = 0;
+            if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1;
+            A [ival]++;
+            lsum = rsum = 0.;
+            memmove ( loutbuf , loutbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( routbuf , routbuf  + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+            memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+            totsamp = 0;
+        }
+        if ( totsamp > sampleWindow )   /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
+            return GAIN_ANALYSIS_ERROR;
+    }
+    if ( num_samples < MAX_ORDER ) {
+        memmove ( linprebuf,                           linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+        memmove ( rinprebuf,                           rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+        memcpy  ( linprebuf + MAX_ORDER - num_samples, left_samples,          num_samples             * sizeof(Float_t) );
+        memcpy  ( rinprebuf + MAX_ORDER - num_samples, right_samples,         num_samples             * sizeof(Float_t) );
+    }
+    else {
+        memcpy  ( linprebuf, left_samples  + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+        memcpy  ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+    }
+
+    return GAIN_ANALYSIS_OK;
+}
+
+
+static Float_t
+analyzeResult ( Uint32_t* Array, size_t len )
+{
+    Uint32_t  elems;
+    Int32_t   upper;
+    size_t    i;
+
+    elems = 0;
+    for ( i = 0; i < len; i++ )
+        elems += Array[i];
+    if ( elems == 0 )
+        return GAIN_NOT_ENOUGH_SAMPLES;
+
+    upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE));
+    for ( i = len; i-- > 0; ) {
+        if ( (upper -= Array[i]) <= 0 )
+            break;
+    }
+
+    return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB);
+}
+
+
+Float_t
+GetTitleGain ( void )
+{
+    Float_t  retval;
+    unsigned int    i;
+
+    retval = analyzeResult ( A, sizeof(A)/sizeof(*A) );
+
+    for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) {
+        B[i] += A[i];
+        A[i]  = 0;
+    }
+
+    for ( i = 0; i < MAX_ORDER; i++ )
+        linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f;
+
+    totsamp = 0;
+    lsum    = rsum = 0.;
+    return retval;
+}
+
+
+Float_t
+GetAlbumGain ( void )
+{
+    return analyzeResult ( B, sizeof(B)/sizeof(*B) );
+}
+
+/* end of replaygain_analysis.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/replaygain_analysis.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,58 @@
+/*
+ *  ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ *  Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  concept and filter values by David Robinson (David@Robinson.org)
+ *    -- blame him if you think the idea is flawed
+ *  coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA
+ *    -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *  minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ *  For an explanation of the concepts and the basic algorithms involved, go to:
+ *    http://www.replaygain.org/
+ */
+
+#ifndef GAIN_ANALYSIS_H
+#define GAIN_ANALYSIS_H
+
+#include <stddef.h>
+
+#define GAIN_NOT_ENOUGH_SAMPLES  -24601
+#define GAIN_ANALYSIS_ERROR           0
+#define GAIN_ANALYSIS_OK              1
+
+#define INIT_GAIN_ANALYSIS_ERROR      0
+#define INIT_GAIN_ANALYSIS_OK         1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float   Float_t;         /* Type used for filtering */
+extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */
+
+int     InitGainAnalysis ( long samplefreq );
+int     AnalyzeSamples   ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels );
+int		ResetSampleFrequency ( long samplefreq );
+Float_t   GetTitleGain     ( void );
+Float_t   GetAlbumGain     ( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GAIN_ANALYSIS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/replaygain_synthesis.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,465 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+/*
+ * This is an aggregation of pieces of code from John Edwards' WaveGain
+ * program.  Mostly cosmetic changes were made; otherwise, the dithering
+ * code is almost untouched and the gain processing was converted from
+ * processing a whole file to processing chunks of samples.
+ *
+ * The original copyright notices for WaveGain's dither.c and wavegain.c
+ * appear below:
+ */
+/*
+ * (c) 2002 John Edwards
+ * mostly lifted from work by Frank Klemm
+ * random functions for dithering.
+ */
+/*
+ * Copyright (C) 2002 John Edwards
+ * Additional code by Magnus Holmgren and Gian-Carlo Pascutto
+ */
+
+#include <string.h> /* for memset() */
+#include <math.h>
+#include "fast_float_math_hack.h"
+#include "replaygain_synthesis.h"
+#include "FLAC/assert.h"
+
+#if defined _MSC_VER
+#define FLAC__INLINE __inline
+#else
+#define FLAC__INLINE
+#endif
+
+/* adjust for compilers that can't understand using LL suffix for int64_t literals */
+#ifdef _MSC_VER
+#define FLAC__I64L(x) x
+#else
+#define FLAC__I64L(x) x##LL
+#endif
+
+
+/*
+ * the following is based on parts of dither.c
+ */
+
+
+/*
+ *  This is a simple random number generator with good quality for audio purposes.
+ *  It consists of two polycounters with opposite rotation direction and different
+ *  periods. The periods are coprime, so the total period is the product of both.
+ *
+ *     -------------------------------------------------------------------------------------------------
+ * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0|
+ * |   -------------------------------------------------------------------------------------------------
+ * |                                                                          |  |  |  |     |        |
+ * |                                                                          +--+--+--+-XOR-+--------+
+ * |                                                                                      |
+ * +--------------------------------------------------------------------------------------+
+ *
+ *     -------------------------------------------------------------------------------------------------
+ *     |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+
+ *     -------------------------------------------------------------------------------------------------   |
+ *       |  |           |  |                                                                               |
+ *       +--+----XOR----+--+                                                                               |
+ *                |                                                                                        |
+ *                +----------------------------------------------------------------------------------------+
+ *
+ *
+ *  The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481,
+ *  which gives a period of 18.410.713.077.675.721.215. The result is the
+ *  XORed values of both generators.
+ */
+
+static unsigned int random_int_()
+{
+	static const unsigned char parity_[256] = {
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+		1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+	};
+	static unsigned int r1_ = 1;
+	static unsigned int r2_ = 1;
+
+	unsigned int t1, t2, t3, t4;
+
+	/* Parity calculation is done via table lookup, this is also available
+	 * on CPUs without parity, can be implemented in C and avoid unpredictable
+	 * jumps and slow rotate through the carry flag operations.
+	 */
+	t3   = t1 = r1_;    t4   = t2 = r2_;
+	t1  &= 0xF5;        t2 >>= 25;
+	t1   = parity_[t1]; t2  &= 0x63;
+	t1 <<= 31;          t2   = parity_[t2];
+
+	return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 );
+}
+
+/* gives a equal distributed random number */
+/* between -2^31*mult and +2^31*mult */
+static double random_equi_(double mult)
+{
+	return mult * (int) random_int_();
+}
+
+/* gives a triangular distributed random number */
+/* between -2^32*mult and +2^32*mult */
+static double random_triangular_(double mult)
+{
+	return mult * ( (double) (int) random_int_() + (double) (int) random_int_() );
+}
+
+
+static const float  F44_0 [16 + 32] = {
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+	(float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0
+};
+
+
+static const float  F44_1 [16 + 32] = {  /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+	(float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+	(float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+	(float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+	(float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+};
+
+
+static const float  F44_2 [16 + 32] = {  /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+	(float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+	(float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+	(float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+	(float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+};
+
+
+static const float  F44_3 [16 + 32] = {  /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+	(float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+	(float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+	(float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+	(float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099
+};
+
+
+static double scalar16_(const float* x, const float* y)
+{
+	return
+		x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] +
+		x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] +
+		x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] +
+		x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15];
+}
+
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype)
+{
+	static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67,  0,  0 };
+	static const float*               F [] = { F44_0, F44_1, F44_2, F44_3 };
+
+	int index;
+
+	if (shapingtype < 0) shapingtype = 0;
+	if (shapingtype > 3) shapingtype = 3;
+	d->ShapingType = (NoiseShaping)shapingtype;
+	index = bits - 11 - shapingtype;
+	if (index < 0) index = 0;
+	if (index > 9) index = 9;
+
+	memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) );
+	memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) );
+
+	d->FilterCoeff = F [shapingtype];
+	d->Mask   = ((FLAC__uint64)-1) << (32 - bits);
+	d->Add    = 0.5     * ((1L << (32 - bits)) - 1);
+	d->Dither = 0.01f*default_dither[index] / (((FLAC__int64)1) << bits);
+	d->LastHistoryIndex = 0;
+}
+
+/*
+ * the following is based on parts of wavegain.c
+ */
+
+static FLAC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
+{
+	union {
+		double d;
+		FLAC__int64 i;
+	} doubletmp;
+	double Sum2;
+	FLAC__int64 val;
+
+#define ROUND64(x)   ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) )
+
+	if(do_dithering) {
+		if(shapingtype == 0) {
+			double  tmp = random_equi_(d->Dither);
+			Sum2 = tmp - d->LastRandomNumber [k];
+			d->LastRandomNumber [k] = (int)tmp;
+			Sum2 = Sum += Sum2;
+			val = ROUND64(Sum2) & d->Mask;
+		}
+		else {
+			Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i);
+			Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2;
+			Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i);
+			val = ROUND64(Sum2) & d->Mask;
+			d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
+		}
+		return val;
+	}
+	else
+		return ROUND64(Sum);
+
+#undef ROUND64
+}
+
+#if 0
+	float        peak = 0.f,
+	             new_peak,
+	             factor_clip
+	double       scale,
+	             dB;
+
+	...
+
+	peak is in the range -32768.0 .. 32767.0
+
+	/* calculate factors for ReplayGain and ClippingPrevention */
+	*track_gain = GetTitleGain() + settings->man_gain;
+	scale = (float) pow(10., *track_gain * 0.05);
+	if(settings->clip_prev) {
+		factor_clip  = (float) (32767./( peak + 1));
+		if(scale < factor_clip)
+			factor_clip = 1.f;
+		else
+			factor_clip /= scale;
+		scale *= factor_clip;
+	}
+	new_peak = (float) peak * scale;
+
+	dB = 20. * log10(scale);
+	*track_gain = (float) dB;
+
+ 	const double scale = pow(10., (double)gain * 0.05);
+#endif
+
+
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
+{
+	static const FLAC__int32 conv_factors_[33] = {
+		-1, /* 0 bits-per-sample (not supported) */
+		-1, /* 1 bits-per-sample (not supported) */
+		-1, /* 2 bits-per-sample (not supported) */
+		-1, /* 3 bits-per-sample (not supported) */
+		268435456, /* 4 bits-per-sample */
+		134217728, /* 5 bits-per-sample */
+		67108864, /* 6 bits-per-sample */
+		33554432, /* 7 bits-per-sample */
+		16777216, /* 8 bits-per-sample */
+		8388608, /* 9 bits-per-sample */
+		4194304, /* 10 bits-per-sample */
+		2097152, /* 11 bits-per-sample */
+		1048576, /* 12 bits-per-sample */
+		524288, /* 13 bits-per-sample */
+		262144, /* 14 bits-per-sample */
+		131072, /* 15 bits-per-sample */
+		65536, /* 16 bits-per-sample */
+		32768, /* 17 bits-per-sample */
+		16384, /* 18 bits-per-sample */
+		8192, /* 19 bits-per-sample */
+		4096, /* 20 bits-per-sample */
+		2048, /* 21 bits-per-sample */
+		1024, /* 22 bits-per-sample */
+		512, /* 23 bits-per-sample */
+		256, /* 24 bits-per-sample */
+		128, /* 25 bits-per-sample */
+		64, /* 26 bits-per-sample */
+		32, /* 27 bits-per-sample */
+		16, /* 28 bits-per-sample */
+		8, /* 29 bits-per-sample */
+		4, /* 30 bits-per-sample */
+		2, /* 31 bits-per-sample */
+		1 /* 32 bits-per-sample */
+	};
+	static const FLAC__int64 hard_clip_factors_[33] = {
+		0, /* 0 bits-per-sample (not supported) */
+		0, /* 1 bits-per-sample (not supported) */
+		0, /* 2 bits-per-sample (not supported) */
+		0, /* 3 bits-per-sample (not supported) */
+		-8, /* 4 bits-per-sample */
+		-16, /* 5 bits-per-sample */
+		-32, /* 6 bits-per-sample */
+		-64, /* 7 bits-per-sample */
+		-128, /* 8 bits-per-sample */
+		-256, /* 9 bits-per-sample */
+		-512, /* 10 bits-per-sample */
+		-1024, /* 11 bits-per-sample */
+		-2048, /* 12 bits-per-sample */
+		-4096, /* 13 bits-per-sample */
+		-8192, /* 14 bits-per-sample */
+		-16384, /* 15 bits-per-sample */
+		-32768, /* 16 bits-per-sample */
+		-65536, /* 17 bits-per-sample */
+		-131072, /* 18 bits-per-sample */
+		-262144, /* 19 bits-per-sample */
+		-524288, /* 20 bits-per-sample */
+		-1048576, /* 21 bits-per-sample */
+		-2097152, /* 22 bits-per-sample */
+		-4194304, /* 23 bits-per-sample */
+		-8388608, /* 24 bits-per-sample */
+		-16777216, /* 25 bits-per-sample */
+		-33554432, /* 26 bits-per-sample */
+		-67108864, /* 27 bits-per-sample */
+		-134217728, /* 28 bits-per-sample */
+		-268435456, /* 29 bits-per-sample */
+		-536870912, /* 30 bits-per-sample */
+		-1073741824, /* 31 bits-per-sample */
+		(FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */
+	};
+	const FLAC__int32 conv_factor = conv_factors_[target_bps];
+	const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps];
+	/*
+	 * The integer input coming in has a varying range based on the
+	 * source_bps.  We want to normalize it to [-1.0, 1.0) so instead
+	 * of doing two multiplies on each sample, we just multiple
+	 * 'scale' by 1/(2^(source_bps-1))
+	 */
+	const double multi_scale = scale / (double)(1u << (source_bps-1));
+
+	FLAC__byte * const start = data_out;
+	unsigned i, channel;
+	const FLAC__int32 *input_;
+	double sample;
+	const unsigned bytes_per_sample = target_bps / 8;
+	const unsigned last_history_index = dither_context->LastHistoryIndex;
+	NoiseShaping noise_shaping = dither_context->ShapingType;
+	FLAC__int64 val64;
+	FLAC__int32 val32;
+	FLAC__int32 uval32;
+	const FLAC__uint32 twiggle = 1u << (target_bps - 1);
+
+	FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS);
+	FLAC__ASSERT(source_bps >= 4);
+	FLAC__ASSERT(target_bps >= 4);
+	FLAC__ASSERT(source_bps <= 32);
+	FLAC__ASSERT(target_bps < 32);
+	FLAC__ASSERT((target_bps & 7) == 0);
+
+	for(channel = 0; channel < channels; channel++) {
+		const unsigned incr = bytes_per_sample * channels;
+		data_out = start + bytes_per_sample * channel;
+		input_ = input[channel];
+		for(i = 0; i < wide_samples; i++, data_out += incr) {
+			sample = (double)input_[i] * multi_scale;
+
+			if(hard_limit) {
+				/* hard 6dB limiting */
+				if(sample < -0.5)
+					sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
+				else if(sample > 0.5)
+					sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
+			}
+			sample *= 2147483647.f;
+
+			val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor;
+
+			val32 = (FLAC__int32)val64;
+			if(val64 >= -hard_clip_factor)
+				val32 = (FLAC__int32)(-(hard_clip_factor+1));
+			else if(val64 < hard_clip_factor)
+				val32 = (FLAC__int32)hard_clip_factor;
+
+			uval32 = (FLAC__uint32)val32;
+			if (unsigned_data_out)
+				uval32 ^= twiggle;
+
+			if (little_endian_data_out) {
+				switch(target_bps) {
+					case 24:
+						data_out[2] = (FLAC__byte)(uval32 >> 16);
+						/* fall through */
+					case 16:
+						data_out[1] = (FLAC__byte)(uval32 >> 8);
+						/* fall through */
+					case 8:
+						data_out[0] = (FLAC__byte)uval32;
+						break;
+				}
+			}
+			else {
+				switch(target_bps) {
+					case 24:
+						data_out[0] = (FLAC__byte)(uval32 >> 16);
+						data_out[1] = (FLAC__byte)(uval32 >> 8);
+						data_out[2] = (FLAC__byte)uval32;
+						break;
+					case 16:
+						data_out[0] = (FLAC__byte)(uval32 >> 8);
+						data_out[1] = (FLAC__byte)uval32;
+						break;
+					case 8:
+						data_out[0] = (FLAC__byte)uval32;
+						break;
+				}
+			}
+		}
+	}
+	dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32;
+
+	return wide_samples * channels * (target_bps/8);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/replaygain_synthesis.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,51 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+
+#include <stdlib.h> /* for size_t */
+#include "FLAC/ordinals.h"
+
+#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2
+
+typedef enum {
+	NOISE_SHAPING_NONE = 0,
+	NOISE_SHAPING_LOW = 1,
+	NOISE_SHAPING_MEDIUM = 2,
+	NOISE_SHAPING_HIGH = 3
+} NoiseShaping;
+
+typedef struct {
+	const float*  FilterCoeff;
+	FLAC__uint64  Mask;
+	double        Add;
+	float         Dither;
+	float         ErrorHistory     [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];  /* 16th order Noise shaping */
+	float         DitherHistory    [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];
+	int           LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS];
+	unsigned      LastHistoryIndex;
+	NoiseShaping  ShapingType;
+} DitherContext;
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype);
+
+/* scale = (float) pow(10., (double)replaygain * 0.05); */
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/tag.c	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,149 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000,2001,2002,2003,2004,2005  Josh Coalson
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * Based on FLAC plugin.c and mpg123 plugin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <audacious/plugin.h>
+#include <audacious/util.h>
+#include <audacious/titlestring.h>
+
+#include "FLAC/metadata.h"
+#include "plugin_common/tags.h"
+#include "charset.h"
+#include "configure.h"
+
+/*
+ * Function local__extname (filename)
+ *
+ *    Return pointer within filename to its extenstion, or NULL if
+ *    filename has no extension.
+ *
+ */
+static char *local__extname(const char *filename)
+{
+	char *ext = strrchr(filename, '.');
+
+	if (ext != NULL)
+		++ext;
+
+	return ext;
+}
+
+static char *local__getstr(char* str)
+{
+	if (str && strlen(str) > 0)
+		return g_strdup(str);
+	return NULL;
+}
+
+static int local__getnum(char* str)
+{
+	if (str && strlen(str) > 0)
+		return atoi(str);
+	return 0;
+}
+
+static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name)
+{
+	if (0 != tags) {
+		const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name);
+		if (0 != utf8) {
+			if(flac_cfg.title.convert_char_set)
+				return convert_from_utf8_to_user(utf8);
+			else
+				return strdup(utf8);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Function flac_format_song_title (tag, filename)
+ *
+ *    Create song title according to `tag' and/or `filename' and
+ *    return it.  The title must be subsequently freed using g_free().
+ *
+ */
+TitleInput *flac_get_tuple(char *filename)
+{
+	TitleInput *input = NULL;
+	FLAC__StreamMetadata *tags;
+	FLAC__StreamMetadata info;
+	char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description;
+	gchar *filename_proxy = g_strdup(filename);
+
+	FLAC_plugin__tags_get(filename_proxy, &tags);
+
+	title       = local__getfield(tags, "TITLE");
+	artist      = local__getfield(tags, "ARTIST");
+	performer   = local__getfield(tags, "PERFORMER");
+	album       = local__getfield(tags, "ALBUM");
+	date        = local__getfield(tags, "DATE");
+	tracknumber = local__getfield(tags, "TRACKNUMBER");
+	genre       = local__getfield(tags, "GENRE");
+	description = local__getfield(tags, "DESCRIPTION");
+
+	input = bmp_title_input_new();
+
+	input->performer = local__getstr(performer);
+	if(!input->performer)
+		input->performer = local__getstr(artist);
+	input->album_name = local__getstr(album);
+	input->track_name = local__getstr(title);
+	input->track_number = local__getnum(tracknumber);
+	input->year = local__getnum(date);
+	input->genre = local__getstr(genre);
+	input->comment = local__getstr(description);
+
+	input->file_name = g_path_get_basename(filename_proxy);
+	input->file_path = g_path_get_dirname(filename_proxy);
+	input->file_ext = local__extname(filename_proxy);
+
+        FLAC__metadata_get_streaminfo(filename, &info);
+
+	input->length = (unsigned)((double)info.data.stream_info.total_samples / (double)info.data.stream_info.sample_rate * 1000.0 + 0.5);
+
+	return input;
+}
+
+gchar *flac_format_song_title(gchar *filename)
+{
+	gchar *ret = NULL;
+	TitleInput *tuple = flac_get_tuple(filename);
+
+	ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), tuple);
+
+	if (!ret) {
+		/*
+		 * Format according to filename.
+		 */
+		ret = g_strdup(g_basename(filename));
+		if (local__extname(ret) != NULL)
+			*(local__extname(ret) - 1) = '\0';	/* removes period */
+	}
+
+	bmp_title_input_free(tuple);
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac113/tag.h	Mon Oct 23 19:51:39 2006 -0700
@@ -0,0 +1,25 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2002,2003,2004,2005  Daisuke Shimamura
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __FLAC__PLUGIN_XMMS__TAG_H__
+#define __FLAC__PLUGIN_XMMS__TAG_H__
+
+TitleInput *flac_get_tuple(gchar * filename);
+gchar *flac_format_song_title(gchar * filename);
+
+#endif