changeset 2356:c5fa65cb26ca

make an experimental copy to update to new sound engine
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Tue, 05 Feb 2008 01:11:50 +0900
parents 0962a6325b9b
children 10a6c273d940
files src/madplug_x/Makefile src/madplug_x/SFMT-alti.c src/madplug_x/SFMT-alti.h src/madplug_x/SFMT-params.h src/madplug_x/SFMT-params19937.h src/madplug_x/SFMT-sse2.c src/madplug_x/SFMT-sse2.h src/madplug_x/SFMT.c src/madplug_x/SFMT.h src/madplug_x/TODO src/madplug_x/configure.c src/madplug_x/decoder.c src/madplug_x/dither.c src/madplug_x/input.c src/madplug_x/input.h src/madplug_x/plugin.c src/madplug_x/plugin.h src/madplug_x/replaygain.c src/madplug_x/replaygain.h src/madplug_x/tuple.c src/madplug_x/tuple.h src/madplug_x/xing.c src/madplug_x/xing.h
diffstat 23 files changed, 5229 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/Makefile	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,20 @@
+PLUGIN = madplug${PLUGIN_SUFFIX}
+
+SRCS = configure.c	\
+       dither.c		\
+       input.c		\
+       replaygain.c	\
+       decoder.c	\
+       tuple.c	        \
+       plugin.c		\
+       xing.c
+
+include ../../buildsys.mk
+include ../../extra.mk
+
+plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
+
+CFLAGS += ${PLUGIN_CFLAGS}
+CPPFLAGS += ${PLUGIN_CPPFLAGS} ${DBUS_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${PANGO_CFLAGS} ${MOWGLI_CFLAGS} ${ARCH_DEFINES} ${SIMD_CFLAGS} ${MAD_CFLAGS} -I../..
+LDFLAGS += ${AUDLDFLAGS}
+LIBS += ${MAD_LIBS} -laudid3tag ${GTK_LIBS} ${GLIB_LIBS} ${PANGO_LIBS} ${MOWGLI_LIBS}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-alti.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,126 @@
+/**
+ * This function represents the recursion formula in AltiVec and BIG ENDIAN.
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param d a 128-bit part of the internal state array
+ * @return output
+ */
+inline static vector unsigned int vec_recursion(vector unsigned int a,
+						vector unsigned int b,
+						vector unsigned int c,
+						vector unsigned int d) {
+
+    const vector unsigned int sl1 = (vector unsigned int){SL1, SL1, SL1, SL1};
+    const vector unsigned int sr1 = (vector unsigned int){SR1, SR1, SR1, SR1};
+#ifdef ONLY64
+    const vector unsigned int mask = (vector unsigned int)
+    {MSK2, MSK1, MSK4, MSK3};
+    const vector unsigned char perm_sl = ALTI_SL2_PERM64;
+    const vector unsigned char perm_sr = ALTI_SR2_PERM64;
+#else
+    const vector unsigned int mask = (vector unsigned int)
+    {MSK1, MSK2, MSK3, MSK4};
+    const vector unsigned char perm_sl = ALTI_SL2_PERM;
+    const vector unsigned char perm_sr = ALTI_SR2_PERM;
+#endif
+    vector unsigned int v, w, x, y, z;
+    x = vec_perm(a, (vector unsigned int)perm_sl, perm_sl);
+    v = a;
+    y = vec_sr(b, sr1);
+    z = vec_perm(c, (vector unsigned int)perm_sr, perm_sr);
+    w = vec_sl(d, sl1);
+    z = vec_xor(z, w);
+    y = vec_and(y, mask);
+    v = vec_xor(v, x);
+    z = vec_xor(z, y);
+    z = vec_xor(z, v);
+    return z;
+}
+
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ */
+inline static void gen_rand_all(void) {
+    int i;
+    vector unsigned int r, r1, r2;
+
+    r1 = sfmt[N - 2].s;
+    r2 = sfmt[N - 1].s;
+    for (i = 0; i < N - POS1; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2);
+	sfmt[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1 - N].s, r1, r2);
+	sfmt[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t array[], int size) {
+    int i, j;
+    vector unsigned int r, r1, r2;
+
+    r1 = sfmt[N - 2].s;
+    r2 = sfmt[N - 1].s;
+    for (i = 0; i < N - POS1; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = vec_recursion(sfmt[i].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    /* main loop */
+    for (; i < size - N; i++) {
+	r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (j = 0; j < 2 * N - size; j++) {
+	sfmt[j].s = array[j + size - N].s;
+    }
+    for (; i < size; i++) {
+	r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	sfmt[j++].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+#ifndef ONLY64
+/**
+ * This function swaps high and low 32-bit of 64-bit integers in user
+ * specified array.
+ *
+ * @param array an 128-bit array to be swapped.
+ * @param size size of 128-bit array.
+ */
+inline static void swap(w128_t array[], int size) {
+    int i;
+    const vector unsigned char perm = (vector unsigned char)
+	{4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11};
+
+    for (i = 0; i < size; i++) {
+	array[i].s = vec_perm(array[i].s, (vector unsigned int)perm, perm);
+    }
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-alti.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,156 @@
+/** 
+ * @file SFMT-alti.h 
+ *
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT)
+ * pseudorandom number generator
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software.
+ * see LICENSE.txt
+ */
+
+#ifndef SFMT_ALTI_H
+#define SFMT_ALTI_H
+
+inline static vector unsigned int vec_recursion(vector unsigned int a,
+						vector unsigned int b,
+						vector unsigned int c,
+						vector unsigned int d)
+    ALWAYSINLINE;
+
+/**
+ * This function represents the recursion formula in AltiVec and BIG ENDIAN.
+ * @param a a 128-bit part of the interal state array
+ * @param b a 128-bit part of the interal state array
+ * @param c a 128-bit part of the interal state array
+ * @param d a 128-bit part of the interal state array
+ * @return output
+ */
+inline static vector unsigned int vec_recursion(vector unsigned int a,
+						vector unsigned int b,
+						vector unsigned int c,
+						vector unsigned int d) {
+
+    const vector unsigned int sl1 = ALTI_SL1;
+    const vector unsigned int sr1 = ALTI_SR1;
+#ifdef ONLY64
+    const vector unsigned int mask = ALTI_MSK64;
+    const vector unsigned char perm_sl = ALTI_SL2_PERM64;
+    const vector unsigned char perm_sr = ALTI_SR2_PERM64;
+#else
+    const vector unsigned int mask = ALTI_MSK;
+    const vector unsigned char perm_sl = ALTI_SL2_PERM;
+    const vector unsigned char perm_sr = ALTI_SR2_PERM;
+#endif
+    vector unsigned int v, w, x, y, z;
+    x = vec_perm(a, (vector unsigned int)perm_sl, perm_sl);
+    v = a;
+    y = vec_sr(b, sr1);
+    z = vec_perm(c, (vector unsigned int)perm_sr, perm_sr);
+    w = vec_sl(d, sl1);
+    z = vec_xor(z, w);
+    y = vec_and(y, mask);
+    v = vec_xor(v, x);
+    z = vec_xor(z, y);
+    z = vec_xor(z, v);
+    return z;
+}
+
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ */
+inline static void gen_rand_all(void) {
+    int i;
+    vector unsigned int r, r1, r2;
+
+    r1 = sfmt[N - 2].s;
+    r2 = sfmt[N - 1].s;
+    for (i = 0; i < N - POS1; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2);
+	sfmt[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1 - N].s, r1, r2);
+	sfmt[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pesudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t *array, int size) {
+    int i, j;
+    vector unsigned int r, r1, r2;
+
+    r1 = sfmt[N - 2].s;
+    r2 = sfmt[N - 1].s;
+    for (i = 0; i < N - POS1; i++) {
+	r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = vec_recursion(sfmt[i].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    /* main loop */
+    for (; i < size - N; i++) {
+	r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+    for (j = 0; j < 2 * N - size; j++) {
+	sfmt[j].s = array[j + size - N].s;
+    }
+    for (; i < size; i++) {
+	r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2);
+	array[i].s = r;
+	sfmt[j++].s = r;
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+#ifndef ONLY64
+#if defined(__APPLE__)
+#define ALTI_SWAP (vector unsigned char) \
+	(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11)
+#else
+#define ALTI_SWAP {4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11}
+#endif
+/**
+ * This function swaps high and low 32-bit of 64-bit integers in user
+ * specified array.
+ *
+ * @param array an 128-bit array to be swaped.
+ * @param size size of 128-bit array.
+ */
+inline static void swap(w128_t *array, int size) {
+    int i;
+    const vector unsigned char perm = ALTI_SWAP;
+
+    for (i = 0; i < size; i++) {
+	array[i].s = vec_perm(array[i].s, (vector unsigned int)perm, perm);
+    }
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-params.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,97 @@
+#ifndef SFMT_PARAMS_H
+#define SFMT_PARAMS_H
+
+#if !defined(MEXP)
+#ifdef __GNUC__
+  #warning "MEXP is not defined. I assume MEXP is 19937."
+#endif
+  #define MEXP 19937
+#endif
+/*-----------------
+  BASIC DEFINITIONS
+  -----------------*/
+/** Mersenne Exponent. The period of the sequence 
+ *  is a multiple of 2^MEXP-1.
+ * #define MEXP 19937 */
+/** SFMT generator has an internal state array of 128-bit integers,
+ * and N is its size. */
+#define N (MEXP / 128 + 1)
+/** N32 is the size of internal state array when regarded as an array
+ * of 32-bit integers.*/
+#define N32 (N * 4)
+/** N64 is the size of internal state array when regarded as an array
+ * of 64-bit integers.*/
+#define N64 (N * 2)
+
+/*----------------------
+  the parameters of SFMT
+  following definitions are in paramsXXXX.h file.
+  ----------------------*/
+/** the pick up position of the array.
+#define POS1 122 
+*/
+
+/** the parameter of shift left as four 32-bit registers.
+#define SL1 18
+ */
+
+/** the parameter of shift left as one 128-bit register. 
+ * The 128-bit integer is shifted by (SL2 * 8) bits. 
+#define SL2 1 
+*/
+
+/** the parameter of shift right as four 32-bit registers.
+#define SR1 11
+*/
+
+/** the parameter of shift right as one 128-bit register. 
+ * The 128-bit integer is shifted by (SL2 * 8) bits. 
+#define SR2 1 
+*/
+
+/** A bitmask, used in the recursion.  These parameters are introduced
+ * to break symmetry of SIMD.
+#define MSK1 0xdfffffefU
+#define MSK2 0xddfecb7fU
+#define MSK3 0xbffaffffU
+#define MSK4 0xbffffff6U 
+*/
+
+/** These definitions are part of a 128-bit period certification vector.
+#define PARITY1	0x00000001U
+#define PARITY2	0x00000000U
+#define PARITY3	0x00000000U
+#define PARITY4	0xc98e126aU
+*/
+
+#if MEXP == 607
+  #include "SFMT-params607.h"
+#elif MEXP == 1279
+  #include "SFMT-params1279.h"
+#elif MEXP == 2281
+  #include "SFMT-params2281.h"
+#elif MEXP == 4253
+  #include "SFMT-params4253.h"
+#elif MEXP == 11213
+  #include "SFMT-params11213.h"
+#elif MEXP == 19937
+  #include "SFMT-params19937.h"
+#elif MEXP == 44497
+  #include "SFMT-params44497.h"
+#elif MEXP == 86243
+  #include "SFMT-params86243.h"
+#elif MEXP == 132049
+  #include "SFMT-params132049.h"
+#elif MEXP == 216091
+  #include "SFMT-params216091.h"
+#else
+#ifdef __GNUC__
+  #error "MEXP is not valid."
+  #undef MEXP
+#else
+  #undef MEXP
+#endif
+
+#endif
+
+#endif /* SFMT_PARAMS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-params19937.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,46 @@
+#ifndef SFMT_PARAMS19937_H
+#define SFMT_PARAMS19937_H
+
+#define POS1	122
+#define SL1	18
+#define SL2	1
+#define SR1	11
+#define SR2	1
+#define MSK1	0xdfffffefU
+#define MSK2	0xddfecb7fU
+#define MSK3	0xbffaffffU
+#define MSK4	0xbffffff6U
+#define PARITY1	0x00000001U
+#define PARITY2	0x00000000U
+#define PARITY3	0x00000000U
+#define PARITY4	0x13c9e684U
+
+
+/* PARAMETERS FOR ALTIVEC */
+#if defined(__APPLE__)	/* For OSX */
+    #define ALTI_SL1	(vector unsigned int)(SL1, SL1, SL1, SL1)
+    #define ALTI_SR1	(vector unsigned int)(SR1, SR1, SR1, SR1)
+    #define ALTI_MSK	(vector unsigned int)(MSK1, MSK2, MSK3, MSK4)
+    #define ALTI_MSK64 \
+	(vector unsigned int)(MSK2, MSK1, MSK4, MSK3)
+    #define ALTI_SL2_PERM \
+	(vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8)
+    #define ALTI_SL2_PERM64 \
+	(vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0)
+    #define ALTI_SR2_PERM \
+	(vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14)
+    #define ALTI_SR2_PERM64 \
+	(vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14)
+#else	/* For OTHER OSs(Linux?) */
+    #define ALTI_SL1	{SL1, SL1, SL1, SL1}
+    #define ALTI_SR1	{SR1, SR1, SR1, SR1}
+    #define ALTI_MSK	{MSK1, MSK2, MSK3, MSK4}
+    #define ALTI_MSK64	{MSK2, MSK1, MSK4, MSK3}
+    #define ALTI_SL2_PERM	{1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8}
+    #define ALTI_SL2_PERM64	{1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0}
+    #define ALTI_SR2_PERM	{7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14}
+    #define ALTI_SR2_PERM64	{15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14}
+#endif	/* For OSX */
+#define IDSTR	"SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6"
+
+#endif /* SFMT_PARAMS19937_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-sse2.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,113 @@
+/** 
+ * @file  SFMT-sse2.c
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) for intel SSE2
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * @note We assume LITTLE ENDIAN in this file
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software, see LICENSE.txt
+ */
+
+/**
+ * This function represents the recursion formula.
+ * @param a a 128-bit part of the interal state array
+ * @param b a 128-bit part of the interal state array
+ * @param c a 128-bit part of the interal state array
+ * @param d a 128-bit part of the interal state array
+ * @param mask 128-bit mask
+ * @return output
+ */
+inline static __m128i mm_recursion(__m128i *a, __m128i *b, 
+				   __m128i c, __m128i d, __m128i mask) {
+    __m128i v, x, y, z;
+    
+    x = _mm_load_si128(a);
+    y = _mm_srli_epi32(*b, SR1);
+    z = _mm_srli_si128(c, SR2);
+    v = _mm_slli_epi32(d, SL1);
+    z = _mm_xor_si128(z, x);
+    z = _mm_xor_si128(z, v);
+    x = _mm_slli_si128(x, SL2);
+    y = _mm_and_si128(y, mask);
+    z = _mm_xor_si128(z, x);
+    z = _mm_xor_si128(z, y);
+    return z;
+}
+
+/**
+ * This function fills the internal state array with psedorandom
+ * integers.
+ */
+inline void gen_rand_all(void) {
+    int i;
+    __m128i r, r1, r2, mask;
+    mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1);
+
+    r1 = _mm_load_si128(&sfmt[N - 2].si);
+    r2 = _mm_load_si128(&sfmt[N - 1].si);
+    for (i = 0; i < N - POS1; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask);
+	_mm_store_si128(&sfmt[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1 - N].si, r1, r2, mask);
+	_mm_store_si128(&sfmt[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+/**
+ * This function fills the user-specified array with psedorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pesudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t array[], int size) {
+    int i, j;
+    __m128i r, r1, r2, mask;
+    mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1);
+
+    r1 = _mm_load_si128(&sfmt[N - 2].si);
+    r2 = _mm_load_si128(&sfmt[N - 1].si);
+    for (i = 0; i < N - POS1; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = mm_recursion(&sfmt[i].si, &array[i + POS1 - N].si, r1, r2, mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    /* main loop */
+    for (; i < size - N; i++) {
+	r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2,
+			 mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (j = 0; j < 2 * N - size; j++) {
+	r = _mm_load_si128(&array[j + size - N].si);
+	_mm_store_si128(&sfmt[j].si, r);
+    }
+    for (; i < size; i++) {
+	r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2,
+			 mask);
+	_mm_store_si128(&array[i].si, r);
+	_mm_store_si128(&sfmt[j++].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT-sse2.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,121 @@
+/** 
+ * @file  SFMT-sse2.h
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) for Intel SSE2
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * @note We assume LITTLE ENDIAN in this file
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software, see LICENSE.txt
+ */
+
+#ifndef SFMT_SSE2_H
+#define SFMT_SSE2_H
+
+inline static __m128i mm_recursion(__m128i *a, __m128i *b, __m128i c,
+				   __m128i d, __m128i mask) ALWAYSINLINE;
+
+/**
+ * This function represents the recursion formula.
+ * @param a a 128-bit part of the interal state array
+ * @param b a 128-bit part of the interal state array
+ * @param c a 128-bit part of the interal state array
+ * @param d a 128-bit part of the interal state array
+ * @param mask 128-bit mask
+ * @return output
+ */
+inline static __m128i mm_recursion(__m128i *a, __m128i *b, 
+				   __m128i c, __m128i d, __m128i mask) {
+    __m128i v, x, y, z;
+    
+    x = _mm_load_si128(a);
+    y = _mm_srli_epi32(*b, SR1);
+    z = _mm_srli_si128(c, SR2);
+    v = _mm_slli_epi32(d, SL1);
+    z = _mm_xor_si128(z, x);
+    z = _mm_xor_si128(z, v);
+    x = _mm_slli_si128(x, SL2);
+    y = _mm_and_si128(y, mask);
+    z = _mm_xor_si128(z, x);
+    z = _mm_xor_si128(z, y);
+    return z;
+}
+
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ */
+inline static void gen_rand_all(void) {
+    int i;
+    __m128i r, r1, r2, mask;
+    mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1);
+
+    r1 = _mm_load_si128(&sfmt[N - 2].si);
+    r2 = _mm_load_si128(&sfmt[N - 1].si);
+    for (i = 0; i < N - POS1; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask);
+	_mm_store_si128(&sfmt[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1 - N].si, r1, r2, mask);
+	_mm_store_si128(&sfmt[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pesudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t *array, int size) {
+    int i, j;
+    __m128i r, r1, r2, mask;
+    mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1);
+
+    r1 = _mm_load_si128(&sfmt[N - 2].si);
+    r2 = _mm_load_si128(&sfmt[N - 1].si);
+    for (i = 0; i < N - POS1; i++) {
+	r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (; i < N; i++) {
+	r = mm_recursion(&sfmt[i].si, &array[i + POS1 - N].si, r1, r2, mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    /* main loop */
+    for (; i < size - N; i++) {
+	r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2,
+			 mask);
+	_mm_store_si128(&array[i].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+    for (j = 0; j < 2 * N - size; j++) {
+	r = _mm_load_si128(&array[j + size - N].si);
+	_mm_store_si128(&sfmt[j].si, r);
+    }
+    for (; i < size; i++) {
+	r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2,
+			 mask);
+	_mm_store_si128(&array[i].si, r);
+	_mm_store_si128(&sfmt[j++].si, r);
+	r1 = r2;
+	r2 = r;
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,618 @@
+/** 
+ * @file  SFMT.c
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT)
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software, see LICENSE.txt
+ */
+#include <string.h>
+#include <assert.h>
+#include "SFMT.h"
+#include "SFMT-params.h"
+
+#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(HAVE_ALTIVEC) && !defined(BIG_ENDIAN64)
+#define BIG_ENDIAN64 1
+#endif
+#if defined(ONLY64) && !defined(BIG_ENDIAN64)
+  #if defined(__GNUC__)
+    #error "-DONLY64 must be specified with -DBIG_ENDIAN64"
+  #endif
+#undef ONLY64
+#endif
+/*------------------------------------------------------
+  128-bit SIMD data type for Altivec, SSE2 or standard C
+  ------------------------------------------------------*/
+#if defined(HAVE_ALTIVEC)
+  #if !defined(__APPLE__)
+    #include <altivec.h>
+  #endif
+/** 128-bit data structure */
+union W128_T {
+    vector unsigned int s;
+    uint32_t u[4];
+};
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+#elif defined(HAVE_SSE2)
+  #include <emmintrin.h>
+
+/** 128-bit data structure */
+union W128_T {
+    __m128i si;
+    uint32_t u[4];
+};
+/** 128-bit data type */
+typedef union W128_T w128_t;
+
+#else
+
+/** 128-bit data structure */
+struct W128_T {
+    uint32_t u[4];
+};
+/** 128-bit data type */
+typedef struct W128_T w128_t;
+
+#endif
+
+/*--------------------------------------
+  FILE GLOBAL VARIABLES
+  internal state, index counter and flag 
+  --------------------------------------*/
+/** the 128-bit internal state array */
+static w128_t sfmt[N];
+/** the 32bit integer pointer to the 128-bit internal state array */
+static uint32_t *psfmt32 = &sfmt[0].u[0];
+#if !defined(BIG_ENDIAN64) || defined(ONLY64)
+/** the 64bit integer pointer to the 128-bit internal state array */
+static uint64_t *psfmt64 = (uint64_t *)&sfmt[0].u[0];
+#endif
+/** index counter to the 32-bit internal state array */
+static int idx;
+/** a flag: it is 0 if and only if the internal state is not yet
+ * initialized. */
+static int initialized = 0;
+/** a parity check vector which certificate the period of 2^{MEXP} */
+static uint32_t parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4};
+
+/*----------------
+  STATIC FUNCTIONS
+  ----------------*/
+inline static int idxof(int i);
+inline static void rshift128(w128_t *out,  w128_t const *in, int shift);
+inline static void lshift128(w128_t *out,  w128_t const *in, int shift);
+inline static void gen_rand_all(void);
+inline static void gen_rand_array(w128_t *array, int size);
+inline static uint32_t func1(uint32_t x);
+inline static uint32_t func2(uint32_t x);
+static void period_certification(void);
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+inline static void swap(w128_t *array, int size);
+#endif
+
+#if defined(HAVE_ALTIVEC)
+  #include "SFMT-alti.h"
+#elif defined(HAVE_SSE2)
+  #include "SFMT-sse2.h"
+#endif
+
+/**
+ * This function simulate a 64-bit index of LITTLE ENDIAN 
+ * in BIG ENDIAN machine.
+ */
+#ifdef ONLY64
+inline static int idxof(int i) {
+    return i ^ 1;
+}
+#else
+inline static int idxof(int i) {
+    return i;
+}
+#endif
+/**
+ * This function simulates SIMD 128-bit right shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
+    uint64_t th, tl, oh, ol;
+
+    th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+    tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+    oh = th >> (shift * 8);
+    ol = tl >> (shift * 8);
+    ol |= th << (64 - shift * 8);
+    out->u[0] = (uint32_t)(ol >> 32);
+    out->u[1] = (uint32_t)ol;
+    out->u[2] = (uint32_t)(oh >> 32);
+    out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void rshift128(w128_t *out, w128_t const *in, int shift) {
+    uint64_t th, tl, oh, ol;
+
+    th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+    tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+    oh = th >> (shift * 8);
+    ol = tl >> (shift * 8);
+    ol |= th << (64 - shift * 8);
+    out->u[1] = (uint32_t)(ol >> 32);
+    out->u[0] = (uint32_t)ol;
+    out->u[3] = (uint32_t)(oh >> 32);
+    out->u[2] = (uint32_t)oh;
+}
+#endif
+/**
+ * This function simulates SIMD 128-bit left shift by the standard C.
+ * The 128-bit integer given in in is shifted by (shift * 8) bits.
+ * This function simulates the LITTLE ENDIAN SIMD.
+ * @param out the output of this function
+ * @param in the 128-bit data to be shifted
+ * @param shift the shift value
+ */
+#ifdef ONLY64
+inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
+    uint64_t th, tl, oh, ol;
+
+    th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]);
+    tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]);
+
+    oh = th << (shift * 8);
+    ol = tl << (shift * 8);
+    oh |= tl >> (64 - shift * 8);
+    out->u[0] = (uint32_t)(ol >> 32);
+    out->u[1] = (uint32_t)ol;
+    out->u[2] = (uint32_t)(oh >> 32);
+    out->u[3] = (uint32_t)oh;
+}
+#else
+inline static void lshift128(w128_t *out, w128_t const *in, int shift) {
+    uint64_t th, tl, oh, ol;
+
+    th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]);
+    tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]);
+
+    oh = th << (shift * 8);
+    ol = tl << (shift * 8);
+    oh |= tl >> (64 - shift * 8);
+    out->u[1] = (uint32_t)(ol >> 32);
+    out->u[0] = (uint32_t)ol;
+    out->u[3] = (uint32_t)(oh >> 32);
+    out->u[2] = (uint32_t)oh;
+}
+#endif
+
+/**
+ * This function represents the recursion formula.
+ * @param r output
+ * @param a a 128-bit part of the internal state array
+ * @param b a 128-bit part of the internal state array
+ * @param c a 128-bit part of the internal state array
+ * @param d a 128-bit part of the internal state array
+ */
+#ifdef ONLY64
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+				w128_t *d) {
+    w128_t x;
+    w128_t y;
+
+    lshift128(&x, a, SL2);
+    rshift128(&y, c, SR2);
+    r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0] 
+	^ (d->u[0] << SL1);
+    r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1] 
+	^ (d->u[1] << SL1);
+    r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2] 
+	^ (d->u[2] << SL1);
+    r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3] 
+	^ (d->u[3] << SL1);
+}
+#else
+inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c,
+				w128_t *d) {
+    w128_t x;
+    w128_t y;
+
+    lshift128(&x, a, SL2);
+    rshift128(&y, c, SR2);
+    r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0] 
+	^ (d->u[0] << SL1);
+    r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1] 
+	^ (d->u[1] << SL1);
+    r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2] 
+	^ (d->u[2] << SL1);
+    r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3] 
+	^ (d->u[3] << SL1);
+}
+#endif
+
+#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2))
+/**
+ * This function fills the internal state array with pseudorandom
+ * integers.
+ */
+inline static void gen_rand_all(void) {
+    int i;
+    w128_t *r1, *r2;
+
+    r1 = &sfmt[N - 2];
+    r2 = &sfmt[N - 1];
+    for (i = 0; i < N - POS1; i++) {
+	do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
+	r1 = r2;
+	r2 = &sfmt[i];
+    }
+    for (; i < N; i++) {
+	do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1 - N], r1, r2);
+	r1 = r2;
+	r2 = &sfmt[i];
+    }
+}
+
+/**
+ * This function fills the user-specified array with pseudorandom
+ * integers.
+ *
+ * @param array an 128-bit array to be filled by pseudorandom numbers.  
+ * @param size number of 128-bit pseudorandom numbers to be generated.
+ */
+inline static void gen_rand_array(w128_t *array, int size) {
+    int i, j;
+    w128_t *r1, *r2;
+
+    r1 = &sfmt[N - 2];
+    r2 = &sfmt[N - 1];
+    for (i = 0; i < N - POS1; i++) {
+	do_recursion(&array[i], &sfmt[i], &sfmt[i + POS1], r1, r2);
+	r1 = r2;
+	r2 = &array[i];
+    }
+    for (; i < N; i++) {
+	do_recursion(&array[i], &sfmt[i], &array[i + POS1 - N], r1, r2);
+	r1 = r2;
+	r2 = &array[i];
+    }
+    for (; i < size - N; i++) {
+	do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
+	r1 = r2;
+	r2 = &array[i];
+    }
+    for (j = 0; j < 2 * N - size; j++) {
+	sfmt[j] = array[j + size - N];
+    }
+    for (; i < size; i++, j++) {
+	do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2);
+	r1 = r2;
+	r2 = &array[i];
+	sfmt[j] = array[i];
+    }
+}
+#endif
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC)
+inline static void swap(w128_t *array, int size) {
+    int i;
+    uint32_t x, y;
+
+    for (i = 0; i < size; i++) {
+	x = array[i].u[0];
+	y = array[i].u[2];
+	array[i].u[0] = array[i].u[1];
+	array[i].u[2] = array[i].u[3];
+	array[i].u[1] = x;
+	array[i].u[3] = y;
+    }
+}
+#endif
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func1(uint32_t x) {
+    return (x ^ (x >> 27)) * (uint32_t)1664525UL;
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t func2(uint32_t x) {
+    return (x ^ (x >> 27)) * (uint32_t)1566083941UL;
+}
+
+/**
+ * This function certificate the period of 2^{MEXP}
+ */
+static void period_certification(void) {
+    int inner = 0;
+    int i, j;
+    uint32_t work;
+
+    for (i = 0; i < 4; i++)
+	inner ^= psfmt32[idxof(i)] & parity[i];
+    for (i = 16; i > 0; i >>= 1)
+	inner ^= inner >> i;
+    inner &= 1;
+    /* check OK */
+    if (inner == 1) {
+	return;
+    }
+    /* check NG, and modification */
+    for (i = 0; i < 4; i++) {
+	work = 1;
+	for (j = 0; j < 32; j++) {
+	    if ((work & parity[i]) != 0) {
+		psfmt32[idxof(i)] ^= work;
+		return;
+	    }
+	    work = work << 1;
+	}
+    }
+}
+
+/*----------------
+  PUBLIC FUNCTIONS
+  ----------------*/
+/**
+ * This function returns the identification string.
+ * The string shows the word size, the Mersenne exponent,
+ * and all parameters of this generator.
+ */
+const char *get_idstring(void) {
+    return IDSTR;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array32() function.
+ * @return minimum size of array used for fill_array32() function.
+ */
+int get_min_array_size32(void) {
+    return N32;
+}
+
+/**
+ * This function returns the minimum size of array used for \b
+ * fill_array64() function.
+ * @return minimum size of array used for fill_array64() function.
+ */
+int get_min_array_size64(void) {
+    return N64;
+}
+
+#ifndef ONLY64
+/**
+ * This function generates and returns 32-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * @return 32-bit pseudorandom number
+ */
+uint32_t gen_rand32(void) {
+    uint32_t r;
+
+    assert(initialized);
+    if (idx >= N32) {
+	gen_rand_all();
+	idx = 0;
+    }
+    r = psfmt32[idx++];
+    return r;
+}
+#endif
+/**
+ * This function generates and returns 64-bit pseudorandom number.
+ * init_gen_rand or init_by_array must be called before this function.
+ * The function gen_rand64 should not be called after gen_rand32,
+ * unless an initialization is again executed. 
+ * @return 64-bit pseudorandom number
+ */
+uint64_t gen_rand64(void) {
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+    uint32_t r1, r2;
+#else
+    uint64_t r;
+#endif
+
+    assert(initialized);
+    assert(idx % 2 == 0);
+
+    if (idx >= N32) {
+	gen_rand_all();
+	idx = 0;
+    }
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+    r1 = psfmt32[idx];
+    r2 = psfmt32[idx + 1];
+    idx += 2;
+    return ((uint64_t)r2 << 32) | r1;
+#else
+    r = psfmt64[idx / 2];
+    idx += 2;
+    return r;
+#endif
+}
+
+#ifndef ONLY64
+/**
+ * This function generates pseudorandom 32-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 624 and a
+ * multiple of four.  The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param array an array where pseudorandom 32-bit integers are filled
+ * by this function.  The pointer to the array must be \b "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer.  In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 32-bit pseudorandom integers to be
+ * generated.  size must be a multiple of 4, and greater than or equal
+ * to (MEXP / 128 + 1) * 4.
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void fill_array32(uint32_t *array, int size) {
+    assert(initialized);
+    assert(idx == N32);
+    assert(size % 4 == 0);
+    assert(size >= N32);
+
+    gen_rand_array((w128_t *)array, size / 4);
+    idx = N32;
+}
+#endif
+
+/**
+ * This function generates pseudorandom 64-bit integers in the
+ * specified array[] by one call. The number of pseudorandom integers
+ * is specified by the argument size, which must be at least 312 and a
+ * multiple of two.  The generation by this function is much faster
+ * than the following gen_rand function.
+ *
+ * For initialization, init_gen_rand or init_by_array must be called
+ * before the first call of this function. This function can not be
+ * used after calling gen_rand function, without initialization.
+ *
+ * @param array an array where pseudorandom 64-bit integers are filled
+ * by this function.  The pointer to the array must be "aligned"
+ * (namely, must be a multiple of 16) in the SIMD version, since it
+ * refers to the address of a 128-bit integer.  In the standard C
+ * version, the pointer is arbitrary.
+ *
+ * @param size the number of 64-bit pseudorandom integers to be
+ * generated.  size must be a multiple of 2, and greater than or equal
+ * to (MEXP / 128 + 1) * 2
+ *
+ * @note \b memalign or \b posix_memalign is available to get aligned
+ * memory. Mac OSX doesn't have these functions, but \b malloc of OSX
+ * returns the pointer to the aligned memory block.
+ */
+void fill_array64(uint64_t *array, int size) {
+    assert(initialized);
+    assert(idx == N32);
+    assert(size % 2 == 0);
+    assert(size >= N64);
+
+    gen_rand_array((w128_t *)array, size / 2);
+    idx = N32;
+
+#if defined(BIG_ENDIAN64) && !defined(ONLY64)
+    swap((w128_t *)array, size /2);
+#endif
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * integer seed.
+ *
+ * @param seed a 32-bit integer used as the seed.
+ */
+void init_gen_rand(uint32_t seed) {
+    int i;
+
+    psfmt32[idxof(0)] = seed;
+    for (i = 1; i < N32; i++) {
+	psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)] 
+					    ^ (psfmt32[idxof(i - 1)] >> 30))
+	    + i;
+    }
+    idx = N32;
+    period_certification();
+    initialized = 1;
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit integers used as the seeds
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ */
+void init_by_array(uint32_t *init_key, int key_length) {
+    int i, j, count;
+    uint32_t r;
+    int lag;
+    int mid;
+    int size = N * 4;
+
+    if (size >= 623) {
+	lag = 11;
+    } else if (size >= 68) {
+	lag = 7;
+    } else if (size >= 39) {
+	lag = 5;
+    } else {
+	lag = 3;
+    }
+    mid = (size - lag) / 2;
+
+    memset(sfmt, 0x8b, sizeof(sfmt));
+    if (key_length + 1 > N32) {
+	count = key_length + 1;
+    } else {
+	count = N32;
+    }
+    r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)] 
+	      ^ psfmt32[idxof(N32 - 1)]);
+    psfmt32[idxof(mid)] += r;
+    r += key_length;
+    psfmt32[idxof(mid + lag)] += r;
+    psfmt32[idxof(0)] = r;
+
+    count--;
+    for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
+	r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] 
+		  ^ psfmt32[idxof((i + N32 - 1) % N32)]);
+	psfmt32[idxof((i + mid) % N32)] += r;
+	r += init_key[j] + i;
+	psfmt32[idxof((i + mid + lag) % N32)] += r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % N32;
+    }
+    for (; j < count; j++) {
+	r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] 
+		  ^ psfmt32[idxof((i + N32 - 1) % N32)]);
+	psfmt32[idxof((i + mid) % N32)] += r;
+	r += i;
+	psfmt32[idxof((i + mid + lag) % N32)] += r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % N32;
+    }
+    for (j = 0; j < N32; j++) {
+	r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)] 
+		  + psfmt32[idxof((i + N32 - 1) % N32)]);
+	psfmt32[idxof((i + mid) % N32)] ^= r;
+	r -= i;
+	psfmt32[idxof((i + mid + lag) % N32)] ^= r;
+	psfmt32[idxof(i)] = r;
+	i = (i + 1) % N32;
+    }
+
+    idx = N32;
+    period_certification();
+    initialized = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/SFMT.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,125 @@
+/** 
+ * @file SFMT.h 
+ *
+ * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom
+ * number generator
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (Hiroshima University)
+ *
+ * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
+ * University. All rights reserved.
+ *
+ * The new BSD License is applied to this software.
+ * see LICENSE.txt
+ *
+ * @note We assume that your system has inttypes.h.  If your system
+ * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t,
+ * and you have to define PRIu64 and PRIx64 in this file as follows:
+ * @verbatim
+ typedef unsigned int uint32_t
+ typedef unsigned long long uint64_t  
+ #define PRIu64 "llu"
+ #define PRIx64 "llx"
+@endverbatim
+ * uint32_t must be exactly 32-bit unsigned integer type (no more, no
+ * less), and uint64_t must be exactly 64-bit unsigned integer type.
+ * PRIu64 and PRIx64 are used for printf function to print 64-bit
+ * unsigned int and 64-bit unsigned int in hexadecimal format.
+ */
+
+#ifndef SFMT_H
+#define SFMT_H
+
+#include <stdio.h>
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+  #include <inttypes.h>
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+  typedef unsigned int uint32_t;
+  typedef unsigned __int64 uint64_t;
+  #define inline __inline
+#else
+  #include <inttypes.h>
+  #if defined(__GNUC__)
+    #define inline __inline__
+  #endif
+#endif
+
+#ifndef PRIu64
+  #if defined(_MSC_VER) || defined(__BORLANDC__)
+    #define PRIu64 "I64u"
+    #define PRIx64 "I64x"
+  #else
+    #define PRIu64 "llu"
+    #define PRIx64 "llx"
+  #endif
+#endif
+
+#if defined(__GNUC__)
+#define ALWAYSINLINE __attribute__((always_inline))
+#endif
+
+uint32_t gen_rand32(void);
+uint64_t gen_rand64(void);
+void fill_array32(uint32_t *array, int size);
+void fill_array64(uint64_t *array, int size);
+void init_gen_rand(uint32_t seed);
+void init_by_array(uint32_t *init_key, int key_length);
+const char *get_idstring(void);
+int get_min_array_size32(void);
+int get_min_array_size64(void);
+
+/* These real versions are due to Isaku Wada */
+/** generates a random number on [0,1]-real-interval */
+inline static double to_real1(uint32_t v)
+{
+    return v * (1.0/4294967295.0); 
+    /* divided by 2^32-1 */ 
+}
+
+/** generates a random number on [0,1]-real-interval */
+inline static double genrand_real1(void)
+{
+    return to_real1(gen_rand32());
+}
+
+/** generates a random number on [0,1)-real-interval */
+inline static double to_real2(uint32_t v)
+{
+    return v * (1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/** generates a random number on [0,1)-real-interval */
+inline static double genrand_real2(void)
+{
+    return to_real2(gen_rand32());
+}
+
+/** generates a random number on (0,1)-real-interval */
+inline static double to_real3(uint32_t v)
+{
+    return (((double)v) + 0.5)*(1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/** generates a random number on (0,1)-real-interval */
+inline static double genrand_real3(void)
+{
+    return to_real3(gen_rand32());
+}
+/** These real versions are due to Isaku Wada */
+
+/** generates a random number on [0,1) with 53-bit resolution*/
+inline static double to_res53(uint64_t v) 
+{ 
+    return v * (1.0/18446744073709551616.0L);
+}
+
+/** generates a random number on [0,1) with 53-bit resolution*/
+inline static double genrand_res53(void) 
+{ 
+    return to_res53(gen_rand64());
+} 
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/TODO	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,16 @@
+-: to do, X: done, x: test needed, ?: uncertainty
+
+X remove info->stop
+X frame_name == ID3_FRAME_COMMENT code highly depends on address of strings. strcmp() is safer way.
+X replace copy right notices
+X import title override feature
+X import neno's configure dialog
+X bug fix: press F5 on not yet played stream hangs.
+- tidy up mad_info_t
+- remove pb_mutex ?
+x replace tag editor with neno's
+X rename files for convenience of taking diff
+- utf8 id3v1 writing ?? (it requires modification to libid3tag.)
+X complete tag deletion code
+- stream recording feature ??
+- simplify info/metadata functions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/configure.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,621 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+/* #define AUD_DEBUG 1 */
+
+#include "plugin.h"
+
+#include <gtk/gtk.h>
+#include <math.h>
+#include <audacious/configdb.h>
+
+static GtkWidget *configure_win = NULL;
+static audmad_config_t *oldconfig = NULL; // undo storage
+
+static audmad_config_t *
+duplicate_config(audmad_config_t *orig)
+{
+    audmad_config_t *copy = g_memdup(orig, sizeof(audmad_config_t));
+
+    copy->replaygain.preamp0_db = g_strdup(orig->replaygain.preamp0_db);
+    copy->replaygain.preamp1_db = g_strdup(orig->replaygain.preamp1_db);
+    copy->replaygain.preamp2_db = g_strdup(orig->replaygain.preamp2_db);
+    copy->id3_format = g_strdup(orig->id3_format);
+
+    return copy;
+}
+
+static void
+dispose_config(audmad_config_t *config)
+{
+    g_free(config->replaygain.preamp0_db);
+    g_free(config->replaygain.preamp1_db);
+    g_free(config->replaygain.preamp2_db);
+    g_free(config->id3_format);
+    g_free(config);
+}
+
+static void
+update_config(gpointer widgets)
+{
+    const gchar *text = NULL;
+
+    AUDDBG("updating\n");
+
+    GtkWidget *dither = g_object_get_data(widgets, "dither");
+    GtkWidget *reopen = g_object_get_data(widgets, "reopen");
+    GtkWidget *fast_playback = g_object_get_data(widgets, "fast_playback");
+    GtkWidget *use_xing = g_object_get_data(widgets, "use_xing");
+    GtkWidget *sjis = g_object_get_data(widgets, "sjis");
+    GtkWidget *show_avg = g_object_get_data(widgets, "show_avg");
+    GtkWidget *RG_enable = g_object_get_data(widgets, "RG_enable");
+    GtkWidget *preamp0 = g_object_get_data(widgets, "preamp0");
+    GtkWidget *preamp1 = g_object_get_data(widgets, "preamp1");
+    GtkWidget *preamp2 = g_object_get_data(widgets, "preamp2");
+    GtkWidget *trackMode = g_object_get_data(widgets, "trackMode");
+    GtkWidget *adaptive_scaler = g_object_get_data(widgets, "adaptive_scaler");
+    GtkWidget *anti_clip = g_object_get_data(widgets, "anti_clip");
+    GtkWidget *title_override = g_object_get_data(widgets, "title_override");
+    GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry");
+
+    //audio
+    audmad_config->dither =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dither));
+    audmad_config->force_reopen_audio =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(reopen));
+
+    //metadata
+    audmad_config->fast_play_time_calc =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fast_playback));
+    audmad_config->use_xing =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_xing));
+    audmad_config->sjis =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sjis));
+
+    //misc
+    audmad_config->show_avg_vbr_bitrate =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_avg));
+
+    //gain control
+    text = gtk_entry_get_text(GTK_ENTRY(preamp0));
+    g_free(audmad_config->replaygain.preamp0_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp0_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp0_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp0_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp0), audmad_config->replaygain.preamp0_db);
+
+    audmad_config->replaygain.enable =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(RG_enable));
+    audmad_config->replaygain.track_mode =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(trackMode));
+
+    text = gtk_entry_get_text(GTK_ENTRY(preamp1));
+    g_free(audmad_config->replaygain.preamp1_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp1_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp1_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp1_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp1), audmad_config->replaygain.preamp1_db);
+
+    text = gtk_entry_get_text(GTK_ENTRY(preamp2));
+    g_free(audmad_config->replaygain.preamp2_db);
+    if(atof(text) > 12.0)
+        audmad_config->replaygain.preamp2_db = g_strdup("+12.0");
+    else if(atof(text) < -12.0)
+        audmad_config->replaygain.preamp2_db = g_strdup("-12.0");
+    else
+        audmad_config->replaygain.preamp2_db = g_strdup(text);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp2), audmad_config->replaygain.preamp2_db);
+
+    audmad_config->replaygain.anti_clip =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(anti_clip));
+    audmad_config->replaygain.adaptive_scaler =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(adaptive_scaler));
+
+    //text
+    audmad_config->title_override =
+        gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override));
+
+    text = gtk_entry_get_text(GTK_ENTRY(title_id3_entry));
+    g_free(audmad_config->id3_format);
+    audmad_config->id3_format = g_strdup(text);
+
+}
+
+static void
+save_config(void)
+{
+    ConfigDb *db = aud_cfg_db_open();
+
+    AUDDBG("saving\n");
+
+    audmad_config_compute(audmad_config);
+
+    //audio
+    aud_cfg_db_set_bool(db, "MAD", "dither", audmad_config->dither);
+    aud_cfg_db_set_bool(db, "MAD", "force_reopen_audio",
+                            audmad_config->force_reopen_audio);
+    //metadata
+    aud_cfg_db_set_bool(db, "MAD", "fast_play_time_calc",
+                        audmad_config->fast_play_time_calc);
+    aud_cfg_db_set_bool(db, "MAD", "use_xing", audmad_config->use_xing);
+    aud_cfg_db_set_bool(db, "MAD", "sjis", audmad_config->sjis);
+
+    //misc
+    aud_cfg_db_set_bool(db, "MAD", "show_avg_vbr_bitrate",
+                            audmad_config->show_avg_vbr_bitrate);
+
+    //gain control
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp0_db",
+                          audmad_config->replaygain.preamp0_db);
+    aud_cfg_db_set_bool(db, "MAD", "RG.enable",
+                        audmad_config->replaygain.enable);
+    aud_cfg_db_set_bool(db, "MAD", "RG.track_mode",
+                        audmad_config->replaygain.track_mode);
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp1_db",
+                          audmad_config->replaygain.preamp1_db);
+    aud_cfg_db_set_string(db, "MAD", "RG.preamp2_db",
+                          audmad_config->replaygain.preamp2_db);
+    aud_cfg_db_set_bool(db, "MAD", "RG.anti_clip",
+                        audmad_config->replaygain.anti_clip);
+    aud_cfg_db_set_bool(db, "MAD", "RG.adaptive_scaler",
+                        audmad_config->replaygain.adaptive_scaler);
+
+    //text
+    aud_cfg_db_set_bool(db, "MAD", "title_override", audmad_config->title_override);
+    aud_cfg_db_set_string(db, "MAD", "id3_format", audmad_config->id3_format);
+
+    aud_cfg_db_close(db);
+}
+
+static void
+configure_win_cancel(GtkWidget *widget, gpointer widgets)
+{
+    AUDDBG("cancel\n");
+    dispose_config(audmad_config);
+    audmad_config = oldconfig;
+    oldconfig = NULL;
+    save_config();
+    gtk_widget_destroy(configure_win);
+    g_object_unref(widgets);
+}
+
+static void
+configure_win_ok(GtkWidget *widget, gpointer widgets)
+{
+    AUDDBG("ok\n");
+    update_config(widgets);
+    save_config();
+    gtk_widget_destroy(configure_win);
+    g_object_unref(widgets);
+    dispose_config(oldconfig);
+    oldconfig = NULL;
+}
+
+static void
+configure_destroy(GtkWidget *w, gpointer data)
+{
+}
+
+static void
+RG_enable_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkWidget *type_vbox = g_object_get_data(widgets, "type_vbox");
+    GtkWidget *rgtypeSet = g_object_get_data(widgets, "rgtypeSet");
+    GtkWidget *preamp1_hbox = g_object_get_data(widgets, "preamp1_hbox");
+    GtkWidget *preamp2_hbox = g_object_get_data(widgets, "preamp2_hbox");
+    GtkWidget *anti_clip = g_object_get_data(widgets, "anti_clip");
+    gboolean enabled;
+
+    update_config(widgets);
+    save_config();
+
+    enabled = audmad_config->replaygain.enable;
+
+    gtk_widget_set_sensitive(type_vbox, enabled);
+    gtk_widget_set_sensitive(rgtypeSet, enabled);
+    gtk_widget_set_sensitive(preamp1_hbox, enabled);
+    gtk_widget_set_sensitive(preamp2_hbox, enabled);
+    gtk_widget_set_sensitive(anti_clip, enabled);
+}
+
+static void
+RG_type_track_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkToggleButton *tb = GTK_TOGGLE_BUTTON(g_object_get_data(widgets, "trackMode"));
+
+    if (gtk_toggle_button_get_active(tb))
+        audmad_config->replaygain.track_mode = TRUE;
+}
+
+static void
+RG_type_album_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkToggleButton *tb = GTK_TOGGLE_BUTTON(g_object_get_data(widgets, "albumMode"));
+
+    if (gtk_toggle_button_get_active(tb))
+        audmad_config->replaygain.track_mode = FALSE;
+}
+
+static void
+simple_update_cb(GtkWidget *w, gpointer widgets)
+{
+    update_config(widgets);
+    save_config();
+}
+
+static void
+entry_changed_cb(GtkWidget *w, gpointer widgets)
+{
+    simple_update_cb(w, widgets);
+}
+
+static void
+title_override_cb(GtkWidget *w, gpointer widgets)
+{
+    GtkWidget *title_override = g_object_get_data(widgets, "title_override");
+    GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry");
+    GtkWidget *title_id3_label = g_object_get_data(widgets, "title_id3_label");
+    gboolean override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override));
+
+    update_config(widgets);
+    save_config();
+
+    gtk_widget_set_sensitive(title_id3_entry, override);
+    gtk_widget_set_sensitive(title_id3_label, override);
+}
+
+void
+audmad_configure(void)
+{
+    GtkWidget *vbox;
+    GtkWidget *bbox, *ok, *cancel;
+    GtkWidget *label, *preamp0_hbox, *preamp1_hbox, *preamp2_hbox;
+    GtkWidget *notebook, *vbox2, *title_id3_label, *title_id3_box;
+
+    GtkWidget *fast_playback, *use_xing, *dither, *sjis, *show_avg, *reopen;
+    GtkWidget *RG_enable, *type_vbox, *rg_vbox, *preamp0, *preamp1, *preamp2;
+    GtkWidget *trackMode, *albumMode, *adaptive_scaler, *anti_clip;
+    GtkWidget *title_override, *title_id3_entry;
+    GtkWidget *rgtypeFrame, *replaygainFrame, *metadataFrame, *audioFrame, *miscFrame;
+    GtkWidget *metadata_vbox, *audio_vbox, *misc_vbox;
+
+    gpointer widgets = g_object_new(G_TYPE_OBJECT, NULL);
+
+    if(oldconfig) {
+        dispose_config(oldconfig);
+        oldconfig = NULL;
+    }
+
+    oldconfig = duplicate_config(audmad_config); //for undo
+
+    if (configure_win != NULL) {
+        gtk_widget_show(configure_win);
+        return;
+    }
+
+    configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_type_hint(GTK_WINDOW(configure_win), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+    g_signal_connect(G_OBJECT(configure_win), "destroy",
+                       G_CALLBACK(gtk_widget_destroyed), &configure_win);
+    g_signal_connect(G_OBJECT(configure_win), "destroy",
+                       G_CALLBACK(configure_destroy), &configure_win);
+
+    gtk_window_set_title(GTK_WINDOW(configure_win),
+                         _("MPEG Audio Plugin Configuration"));
+    gtk_window_set_policy(GTK_WINDOW(configure_win), FALSE, FALSE, FALSE);
+    gtk_container_border_width(GTK_CONTAINER(configure_win), 10);
+
+    vbox = gtk_vbox_new(FALSE, 10);
+    gtk_container_add(GTK_CONTAINER(configure_win), vbox);
+
+    notebook = gtk_notebook_new();
+    gtk_box_pack_start(GTK_BOX(vbox), notebook, FALSE, FALSE, 0);
+
+
+    /********************************************************************************/
+
+
+    vbox2 = gtk_vbox_new(FALSE, 5);
+
+    // audio frame
+    audioFrame = gtk_frame_new(_("Audio Settings"));
+    gtk_container_border_width(GTK_CONTAINER(audioFrame), 5);
+
+    audio_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(audioFrame), audio_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), audioFrame);
+
+    dither = gtk_check_button_new_with_label
+        (_("Dither output when rounding to 16-bit"));
+    g_object_set_data(widgets, "dither", dither);
+    gtk_box_pack_start(GTK_BOX(audio_vbox), dither, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dither),
+                                 audmad_config->dither);
+    g_signal_connect(G_OBJECT(dither), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    reopen = gtk_check_button_new_with_label(_("Force reopen audio when audio type changed"));
+    g_object_set_data(widgets, "reopen", reopen);
+    gtk_box_pack_start(GTK_BOX(audio_vbox), reopen, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reopen),
+                                 audmad_config->force_reopen_audio);
+    g_signal_connect(G_OBJECT(reopen), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+
+    // metadata frame
+    metadataFrame = gtk_frame_new(_("Metadata Settings"));
+    gtk_container_border_width(GTK_CONTAINER(metadataFrame), 5);
+
+    metadata_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(metadataFrame), metadata_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), metadataFrame);
+
+    fast_playback =
+        gtk_check_button_new_with_label(_("Enable fast play-length calculation"));
+    g_object_set_data(widgets, "fast_playback", fast_playback);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), fast_playback, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fast_playback),
+                                 audmad_config->fast_play_time_calc);
+    g_signal_connect(G_OBJECT(fast_playback), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    use_xing = gtk_check_button_new_with_label(_("Parse XING headers"));
+    g_object_set_data(widgets, "use_xing", use_xing);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), use_xing, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_xing),
+                                 audmad_config->use_xing);
+    g_signal_connect(G_OBJECT(use_xing), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    sjis = gtk_check_button_new_with_label(_("Use SJIS to write ID3 tags (not recommended)"));
+    g_object_set_data(widgets, "sjis", sjis);
+    gtk_box_pack_start(GTK_BOX(metadata_vbox), sjis, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sjis), audmad_config->sjis);
+    g_signal_connect(G_OBJECT(sjis), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    // misc frame
+    miscFrame = gtk_frame_new(_("Miscellaneous Settings"));
+    gtk_container_border_width(GTK_CONTAINER(miscFrame), 5);
+
+    misc_vbox = gtk_vbox_new(FALSE, 5);
+
+    gtk_container_add(GTK_CONTAINER(miscFrame), misc_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), miscFrame);
+
+
+    show_avg = gtk_check_button_new_with_label(_("Display average bitrate for VBR"));
+    g_object_set_data(widgets, "show_avg", show_avg);
+    gtk_box_pack_start(GTK_BOX(misc_vbox), show_avg, FALSE, FALSE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_avg),
+                                 audmad_config->show_avg_vbr_bitrate);
+    g_signal_connect(G_OBJECT(show_avg), "clicked", G_CALLBACK(simple_update_cb), widgets);
+
+    // add to notebook
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("General")));
+
+
+
+    /*********************************************************************************/
+
+
+    vbox2 = gtk_vbox_new(FALSE, 10);
+    gtk_container_border_width(GTK_CONTAINER(vbox2), 5);
+
+    // overall preamp
+    label = gtk_label_new(_("Base gain (dB):"));
+    preamp0_hbox = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox2), preamp0_hbox, TRUE, TRUE, 0);
+
+    preamp0 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp0", preamp0);
+    gtk_widget_set_usize(preamp0, 80, -1);
+
+    gtk_entry_set_text(GTK_ENTRY(preamp0), audmad_config->replaygain.preamp0_db);
+    gtk_box_pack_start(GTK_BOX(preamp0_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp0_hbox), preamp0, FALSE, TRUE, 0);
+    g_signal_connect(preamp0, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+    // replaygain frame
+    replaygainFrame = gtk_frame_new(_("ReplayGain Settings"));
+    gtk_container_border_width(GTK_CONTAINER(replaygainFrame), 5);
+    g_object_set_data(widgets, "replaygainFrame", replaygainFrame);    
+
+    rg_vbox = gtk_vbox_new(FALSE, 5);
+    g_object_set_data(widgets, "rg_vbox", rg_vbox);
+    gtk_container_add(GTK_CONTAINER(replaygainFrame), rg_vbox);
+    gtk_container_add(GTK_CONTAINER(vbox2), replaygainFrame);
+
+
+    // enable/disable replaygain
+    RG_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing"));
+    g_object_set_data(widgets, "RG_enable", RG_enable);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), RG_enable, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(RG_enable),
+                                 audmad_config->replaygain.enable);
+
+    g_signal_connect(G_OBJECT(RG_enable), "clicked", G_CALLBACK(RG_enable_cb), widgets);
+
+
+    // replaygin type radio button
+    rgtypeFrame = gtk_frame_new(_("ReplayGain Type"));
+    g_object_set_data(widgets, "rgtypeFrame", rgtypeFrame);
+
+    type_vbox = gtk_vbox_new(FALSE, 5);
+    g_object_set_data(widgets, "type_vbox", type_vbox);
+
+    gtk_container_set_border_width(GTK_CONTAINER(type_vbox), 5);
+    gtk_container_add(GTK_CONTAINER(rgtypeFrame), type_vbox);
+    gtk_container_add(GTK_CONTAINER(rg_vbox), rgtypeFrame);
+
+    trackMode = gtk_radio_button_new_with_label(NULL, _("Use Track Gain"));
+    g_object_set_data(widgets, "trackMode", trackMode);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(trackMode), audmad_config->replaygain.track_mode);
+    gtk_box_pack_start(GTK_BOX(type_vbox), trackMode, FALSE, FALSE, 0);
+
+
+    albumMode =
+        gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(trackMode)),
+                                        _("Use Album Gain"));
+    g_object_set_data(widgets, "albumMode", albumMode);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(albumMode), !audmad_config->replaygain.track_mode);
+    gtk_box_pack_start(GTK_BOX(type_vbox), albumMode, FALSE, FALSE, 0);
+
+    // xxx 
+    g_signal_connect(G_OBJECT(trackMode), "toggled", G_CALLBACK(RG_type_track_cb), widgets);
+    g_signal_connect(G_OBJECT(albumMode), "toggled", G_CALLBACK(RG_type_album_cb), widgets);
+
+
+
+    // preamp for the files with RG info
+    label = gtk_label_new(_("Pre-gain with RG info (dB):"));
+    preamp1_hbox = gtk_hbox_new(FALSE, 5);
+    g_object_set_data(widgets, "preamp1_hbox", preamp1_hbox);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), preamp1_hbox, TRUE, TRUE, 0);
+
+    preamp1 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp1", preamp1);
+    gtk_widget_set_usize(preamp1, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(preamp1),
+                       audmad_config->replaygain.preamp1_db);
+    gtk_box_pack_start(GTK_BOX(preamp1_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp1_hbox), preamp1, FALSE, TRUE, 0);
+    g_signal_connect(preamp1, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+
+    // preamp for the files without RG info
+    label = gtk_label_new(_("Pre-gain without RG info (dB):"));
+    preamp2_hbox = gtk_hbox_new(FALSE, 5);
+    g_object_set_data(widgets, "preamp2_hbox", preamp2_hbox);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), preamp2_hbox, TRUE, TRUE, 0);
+
+    preamp2 = gtk_entry_new();
+    g_object_set_data(widgets, "preamp2", preamp2);
+    gtk_widget_set_usize(preamp2, 80, -1);
+    gtk_entry_set_text(GTK_ENTRY(preamp2),
+                       audmad_config->replaygain.preamp2_db);
+    gtk_box_pack_start(GTK_BOX(preamp2_hbox), label, FALSE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(preamp2_hbox), preamp2, FALSE, TRUE, 0);
+    g_signal_connect(preamp2, "changed", G_CALLBACK(entry_changed_cb), widgets);
+
+
+    // clipping prevention
+    anti_clip = gtk_check_button_new_with_label(_("Enable peak info clip prevention"));
+    g_object_set_data(widgets, "anti_clip", anti_clip);
+    gtk_box_pack_start(GTK_BOX(rg_vbox), anti_clip, TRUE, TRUE, 0);
+
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(anti_clip),
+                                 audmad_config->replaygain.anti_clip);
+
+    g_signal_connect(G_OBJECT(anti_clip), "clicked",
+                     G_CALLBACK(simple_update_cb), widgets);
+
+    // sensitivity
+    if(!audmad_config->replaygain.enable) {
+        gtk_widget_set_sensitive(type_vbox, FALSE);
+        gtk_widget_set_sensitive(rgtypeFrame, FALSE);
+        gtk_widget_set_sensitive(preamp1_hbox, FALSE);
+        gtk_widget_set_sensitive(preamp2_hbox, FALSE);
+        gtk_widget_set_sensitive(anti_clip, FALSE);
+    }
+    /* end of replaygainFrame */
+
+
+    // adaptive scale
+    adaptive_scaler = gtk_check_button_new_with_label(_("Enable adaptive scaler clip prevention"));
+    g_object_set_data(widgets, "adaptive_scaler", adaptive_scaler);
+    gtk_box_pack_start(GTK_BOX(vbox2), adaptive_scaler, TRUE, TRUE, 0);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(adaptive_scaler),
+                                 audmad_config->replaygain.adaptive_scaler);
+    g_signal_connect(G_OBJECT(adaptive_scaler), "clicked",
+                     G_CALLBACK(simple_update_cb), widgets);
+
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("Gain Control")));
+
+
+    /*********************************************************************************/
+
+
+    vbox2 = gtk_vbox_new(FALSE, 5);
+
+    title_override = gtk_check_button_new_with_label(_("Override generic titles"));
+    g_object_set_data(widgets, "title_override", title_override);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_override),
+                                 audmad_config->title_override);
+    gtk_box_pack_start(GTK_BOX(vbox2), title_override, FALSE,
+                       FALSE, 0);
+    g_signal_connect(G_OBJECT(title_override), "clicked",
+                     G_CALLBACK(title_override_cb), widgets);
+
+    title_id3_box = gtk_hbox_new(FALSE, 5);
+    gtk_box_pack_start(GTK_BOX(vbox2), title_id3_box, FALSE, FALSE, 0);
+
+    title_id3_label = gtk_label_new(_("ID3 format:"));
+    g_object_set_data(widgets, "title_id3_label", title_id3_label);
+    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_label, FALSE, FALSE, 0);
+    gtk_widget_set_sensitive(title_id3_label, audmad_config->title_override);
+
+    title_id3_entry = gtk_entry_new();
+    g_object_set_data(widgets, "title_id3_entry", title_id3_entry);
+    gtk_entry_set_text(GTK_ENTRY(title_id3_entry), audmad_config->id3_format);
+    gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_entry, TRUE, TRUE, 0);
+    g_signal_connect(title_id3_entry, "changed", G_CALLBACK(entry_changed_cb), widgets);
+    gtk_widget_set_sensitive(title_id3_entry, audmad_config->title_override);
+
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("Title")));
+
+
+
+    /*********************************************************************************/
+
+
+    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);
+
+    cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+
+    g_signal_connect(G_OBJECT(cancel), "clicked",
+                     G_CALLBACK(configure_win_cancel), widgets);
+
+    gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+
+    ok = gtk_button_new_from_stock(GTK_STOCK_OK);
+
+    g_signal_connect(G_OBJECT(ok), "clicked",
+                     G_CALLBACK(configure_win_ok), widgets);
+
+    gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+    gtk_widget_grab_default(ok);
+
+    gtk_widget_show_all(configure_win);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/decoder.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,733 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+/* #define AUD_DEBUG 1 */
+
+#include <math.h>
+#include <assert.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include <audacious/plugin.h>
+#include <audacious/output.h>
+#include <audacious/util.h>
+#include <sys/time.h>
+#include "plugin.h"
+#include "input.h"
+
+#define BUFFER_SIZE 16*1024
+#define N_AVERAGE_FRAMES 10
+
+extern int triangular_dither_noise(int nbits);
+
+/**
+ * Scale PCM data
+ */
+static inline signed int
+scale(mad_fixed_t sample, struct mad_info_t *file_info)
+{
+    gdouble scale = -1;
+    static double a_scale = -1;
+    static int iter = 0;
+
+    if (audmad_config->replaygain.enable) {
+        if (file_info->has_replaygain) {
+            // apply track gain if it is available and track mode is specified
+            if(file_info->replaygain_track_scale != -1) {
+                scale = file_info->replaygain_track_scale;
+            }
+            // apply album gain if available
+            if(!audmad_config->replaygain.track_mode &&
+               file_info->replaygain_album_scale != -1) {
+                scale = file_info->replaygain_album_scale;
+            }
+
+            // apply preamp1
+            scale *= audmad_config->replaygain.preamp1_scale;
+
+            if (audmad_config->replaygain.anti_clip) {
+#ifdef AUD_DEBUG
+                if(iter % 100000 == 0)
+                    AUDDBG("track_peak = %f\n", file_info->replaygain_track_peak);
+#endif
+                if(scale * file_info->replaygain_track_peak >= 1.0)
+                    scale = 1.0 / file_info->replaygain_track_peak;
+            }
+        }
+        else {
+            // apply preamp2 for files without RG info
+            scale = audmad_config->replaygain.preamp2_scale;
+        }
+    }
+    else {
+        scale = 1.0;
+    }
+
+    // apply global gain
+    if (audmad_config->replaygain.preamp0_scale != 1)
+        scale = scale * audmad_config->replaygain.preamp0_scale;
+
+    // adaptive scaler clip prevention
+    if (audmad_config->replaygain.adaptive_scaler) {
+        double x;
+        double a = 0.1;
+        int interval = 10000;
+
+        if(a_scale == -1.0)
+            a_scale = scale;
+
+        x = mad_f_todouble(sample) * a_scale;
+
+        // clippling avoidance
+        if(x > 1.0) {
+            a_scale = a_scale + a * (1.0 - x);
+            AUDDBG("down: x = %f a_scale = %f\n", x, a_scale);
+        }
+        // slowly go back to defined scale
+        else if(iter % interval == 0 && a_scale < scale){
+            a_scale = a_scale + 1.0e-4;
+            AUDDBG("up: a_scale = %f\n", a_scale);
+        }
+
+        x = mad_f_todouble(sample) * a_scale;
+        sample = x * (MAD_F_ONE);
+    }
+    else {
+        a_scale = scale;
+        sample *= scale;
+    }
+
+    iter++;
+
+    int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
+
+    /* round */
+    /* add half of the bits_to_loose range to round */
+    sample += (1L << (n_bits_to_loose - 1));
+
+#ifdef DEBUG_DITHER
+    mad_fixed_t no_dither = sample;
+#endif
+
+    /* dither one bit of actual output */
+    if (audmad_config->dither) {
+        int dither = triangular_dither_noise(n_bits_to_loose + 1);
+        sample += dither;
+    }
+
+    /* clip */
+    /* make sure we are between -1 and 1 */
+    if (sample >= MAD_F_ONE) {
+        sample = MAD_F_ONE - 1;
+    }
+    else if (sample < -MAD_F_ONE) {
+        sample = -MAD_F_ONE;
+    }
+
+    /* quantize */
+    /*
+     * Turn our mad_fixed_t into an integer.
+     * Shift all but 16-bits of the fractional part
+     * off the right hand side and shift an extra place
+     * to get the sign bit.
+     */
+    sample >>= n_bits_to_loose;
+#ifdef DEBUG_DITHER
+    static int n_zeros = 0;
+    no_dither >>= n_bits_to_loose;
+    if (no_dither - sample == 0)
+        n_zeros++;
+    else {
+        g_message("dither: %d %d", n_zeros, no_dither - sample);
+        n_zeros = 0;
+    }
+#endif
+    return sample;
+}
+
+void
+write_output(struct mad_info_t *info, struct mad_pcm *pcm,
+             struct mad_header *header)
+{
+    unsigned int nsamples;
+    mad_fixed_t const *left_ch, *right_ch;
+    char *output;
+    int olen = 0;
+    int pos = 0;
+
+    nsamples = pcm->length;
+    left_ch = pcm->samples[0];
+    right_ch = pcm->samples[1];
+    olen = nsamples * MAD_NCHANNELS(header) * 2;
+    output = (char *) g_malloc(olen * sizeof(char));
+
+    while (nsamples--) {
+        signed int sample;
+        /* output sample(s) in 16-bit signed little-endian PCM */
+        sample = scale(*left_ch++, info);
+        output[pos++] = (sample >> 0) & 0xff;
+        output[pos++] = (sample >> 8) & 0xff;
+
+        if (MAD_NCHANNELS(header) == 2) {
+            sample = scale(*right_ch++, info);
+            output[pos++] = (sample >> 0) & 0xff;
+            output[pos++] = (sample >> 8) & 0xff;
+        }
+    }
+    assert(pos == olen);
+    if (!info->playback->playing) {
+        g_free(output);
+        return;
+    }
+    info->playback->pass_audio(info->playback,
+                  FMT_S16_LE, MAD_NCHANNELS(header), olen, output, &(info->playback->playing));
+    g_free(output);
+}
+
+/**
+ * Decode all headers in the file and fill in stats
+ * @return FALSE if scan failed.
+ */
+gboolean
+scan_file(struct mad_info_t * info, gboolean fast)
+{
+    struct mad_stream stream;
+    struct mad_header header;
+    int remainder = 0;
+    int data_used = 0;
+    int len = 0;
+    int tagsize = 0;
+    unsigned char buffer[BUFFER_SIZE];
+    struct mad_frame frame;     /* to read xing data */
+    gboolean has_xing = FALSE;
+    guint bitrate_frames = 0;
+    double xing_bitrate = 0.0;
+    double accum_bitrate = 0.0;
+
+    mad_stream_init(&stream);
+    mad_stream_options(&stream, 0); // check CRC
+    mad_header_init(&header);
+    mad_frame_init(&frame);
+    xing_init(&info->xing);
+
+    info->bitrate = 0;
+    info->pos = mad_timer_zero;
+    info->duration = mad_timer_zero; // should be cleared before loop, if we use it as break condition.
+
+    if(info->fileinfo_request == TRUE) {
+        aud_tuple_associate_int(info->tuple, FIELD_LENGTH, NULL, -1);
+        info->fileinfo_request = FALSE;
+    }
+
+    AUDDBG("f: scan_file\n");
+    AUDDBG("scan_file frames = %d\n", info->frames);
+
+    while (1) {
+        remainder = stream.bufend - stream.next_frame;
+	
+        /*
+           if (remainder >= BUFFER_SIZE)
+           {
+           printf("oh dear.. remainder = %d\n", remainder);
+           }
+         */
+
+        memcpy(buffer, stream.this_frame, remainder);
+        len = input_get_data(info, buffer + remainder,
+                             BUFFER_SIZE - remainder);
+
+        if (len <= 0) {
+            AUDDBG("scan_file: len <= 0 len = %d\n", len);
+            break;
+        }
+
+        mad_stream_buffer(&stream, buffer, len + remainder);
+
+        while (!fast || (fast && info->frames < N_AVERAGE_FRAMES)) {
+            if (mad_header_decode(&header, &stream) == -1) {
+                if (stream.error == MAD_ERROR_BUFLEN) {
+                    break;
+                }
+                if (!MAD_RECOVERABLE(stream.error)) {
+                    AUDDBG("(fatal) error decoding header %d: %s\n",
+                              info->frames, mad_stream_errorstr(&stream));
+                    AUDDBG("remainder = %d\n", remainder);
+                    AUDDBG("len = %d\n", len);
+                    break;
+                }
+                if (stream.error == MAD_ERROR_LOSTSYNC) {
+                    /* ignore LOSTSYNC due to ID3 tags */
+                    tagsize = id3_tag_query(stream.this_frame,
+                                            stream.bufend -
+                                            stream.this_frame);
+                    if (tagsize > 0) {
+                        AUDDBG("skipping id3_tag: %d\n", tagsize);
+                        mad_stream_skip(&stream, tagsize);
+                        continue;
+                    }
+                }
+
+                AUDDBG("(recovered) error decoding header %d: %s\n",
+                          info->frames, mad_stream_errorstr(&stream));
+                AUDDBG("remainder = %d\n", remainder);
+                AUDDBG("len = %d\n", len);
+
+                continue;
+            }
+            info->frames++;
+
+#ifdef DEBUG_INTENSIVELY
+            AUDDBG("header bitrate = %ld\n", header.bitrate);
+            AUDDBG("duration = %ul\n",
+                      mad_timer_count(header.duration,
+                                      MAD_UNITS_MILLISECONDS));
+            AUDDBG("size = %d\n", stream.next_frame - stream.this_frame);
+#endif
+            if(aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL) == -1)
+                mad_timer_add(&info->duration, header.duration);
+            else {
+                gint length = aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL);
+
+                info->duration.seconds = length / 1000;
+                info->duration.fraction = length % 1000;
+            }
+            data_used += stream.next_frame - stream.this_frame;
+            if (info->frames == 1) {
+                /* most of these *should* remain constant */
+                info->bitrate = header.bitrate;
+                info->freq = header.samplerate;
+                info->channels = MAD_NCHANNELS(&header);
+                info->mpeg_layer = header.layer;
+                info->mode = header.mode;
+
+                if (audmad_config->use_xing) {
+                    frame.header = header;
+                    if (mad_frame_decode(&frame, &stream) == -1) {
+                        AUDDBG("xing frame decode failed\n");
+                        goto no_xing;
+                    }
+                    if (xing_parse(&info->xing, stream.anc_ptr, stream.anc_bitlen) == 0) {
+                        AUDDBG("xing header found\n");
+                        has_xing = TRUE;
+                        info->vbr = TRUE;   /* otherwise xing header would have been 'Info' */
+
+                        AUDDBG("xing: bytes = %ld frames = %ld\n", info->xing.bytes, info->xing.frames);
+
+                        /* we have enough info to calculate bitrate and duration */
+                        if(info->xing.bytes && info->xing.frames) {
+                            xing_bitrate = 8 * (double)info->xing.bytes * 38 / (double)info->xing.frames; //38fps in MPEG1.
+#ifdef AUD_DEBUG
+                            {
+                                gint tmp = (gint)(info->xing.bytes * 8 / xing_bitrate);
+                                AUDDBG("xing: bitrate = %4.1f kbps\n", xing_bitrate / 1000);
+                                AUDDBG("xing: duration = %d:%02d\n", tmp / 60, tmp % 60);
+                            }
+#endif
+                        }
+                        continue;
+                    }
+#ifdef AUD_DEBUG
+                    else {
+                        AUDDBG("no usable xing header\n");
+                        continue;
+                    }
+#endif
+                } /* xing */
+
+            }
+            else {
+                /* perhaps we have a VBR file */
+                if (info->bitrate != header.bitrate)
+                    info->vbr = TRUE;
+                if (info->vbr) {
+                    accum_bitrate += (double)header.bitrate;
+                    bitrate_frames++;
+                }
+                /* check for changin layer/samplerate/channels */
+                if (info->mpeg_layer != header.layer)
+                    g_warning("layer varies!!");
+                if (info->freq != header.samplerate)
+                    g_warning("samplerate varies!!");
+                if (info->channels != MAD_NCHANNELS(&header))
+                    g_warning("number of channels varies!!");
+            }
+        no_xing:
+            if (fast && info->frames >= N_AVERAGE_FRAMES) {
+                float frame_size = ((double) data_used) / N_AVERAGE_FRAMES;
+
+                AUDDBG("bitrate = %ld samplerate = %d\n", header.bitrate, header.samplerate);
+                AUDDBG("data_used = %d info->frames = %d info->size = %d tagsize = %d frame_size = %lf\n",
+                          data_used, info->frames, info->size, tagsize, frame_size);
+
+                if(info->size != 0)
+                    info->frames = (info->size - tagsize) / frame_size;
+
+                AUDDBG("info->frames = %d\n", info->frames);
+
+                if(aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL) == -1) {
+                    if(xing_bitrate > 0.0) {
+                        /* calc duration with xing info */
+                        double tmp = 8 * (double)info->xing.bytes * 1000 / xing_bitrate;
+                        info->duration.seconds = (guint)(tmp / 1000);
+                        info->duration.fraction = (guint)(tmp - info->duration.seconds * 1000);
+                    }
+                    else {
+                        info->duration.seconds /= N_AVERAGE_FRAMES;
+                        info->duration.fraction /= N_AVERAGE_FRAMES;
+                        mad_timer_multiply(&info->duration, info->frames);
+                    }
+                }
+                else {
+                    gint length = aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL);
+
+                    info->duration.seconds = length / 1000;
+                    info->duration.fraction = length % 1000;
+                }
+#ifdef AUD_DEBUG
+                AUDDBG("using fast playtime calculation\n");
+                AUDDBG("data used = %d [tagsize=%d framesize=%f]\n",
+                          data_used, tagsize, frame_size);
+                AUDDBG("frames = %d, frequency = %d, channels = %d\n",
+                          info->frames, info->freq, info->channels);
+                long millis = mad_timer_count(info->duration,
+                                              MAD_UNITS_MILLISECONDS);
+                AUDDBG("duration = %ld:%02ld\n", millis / 1000 / 60, (millis / 1000) % 60);
+#endif                          /* DEBUG */
+                break;
+            }
+        } /* while */
+        if (stream.error != MAD_ERROR_BUFLEN)
+            break;
+    }
+
+    if (info->xing.frames)
+        info->frames = info->xing.frames;
+
+    if (info->vbr && xing_bitrate != 0) {
+        info->bitrate = (guint)xing_bitrate;
+    }
+    else if (info->vbr && xing_bitrate == 0 && bitrate_frames != 0) {
+        info->bitrate = accum_bitrate / bitrate_frames;
+    }
+    
+    aud_tuple_associate_int(info->tuple, FIELD_BITRATE, NULL, info->bitrate / 1000);
+
+    mad_frame_finish(&frame);
+    mad_header_finish(&header);
+    mad_stream_finish(&stream);
+    xing_finish(&info->xing);
+
+    AUDDBG("scan_file: info->frames = %d\n", info->frames);
+    AUDDBG("e: scan_file\n");
+
+    return (info->frames != 0 || info->remote == TRUE);
+}
+
+/* sanity check for audio open parameters */
+static gboolean
+check_audio_param(struct mad_info_t *info)
+{
+    if(info->fmt < FMT_U8 || info->fmt > FMT_S16_NE)
+        return FALSE;
+    if(info->freq < 0) // not sure about maximum frequency. --yaz
+        return FALSE;
+    if(info->channels < 1 || info->channels > 2)
+        return FALSE;
+
+    return TRUE;
+}
+
+gpointer
+decode_loop(gpointer arg)
+{
+    unsigned char buffer[BUFFER_SIZE];
+    int len;
+    gboolean seek_skip = FALSE;
+    int remainder = 0;
+    gint tlen;
+    unsigned int iteration = 0;
+
+    /* mad structs */
+    struct mad_stream stream;
+    struct mad_frame frame;
+    struct mad_synth synth;
+
+    /* track info is passed in as thread argument */
+    struct mad_info_t *info = (struct mad_info_t *) arg;
+
+    AUDDBG("f: decode\n");
+
+    /* init mad stuff */
+    mad_frame_init(&frame);
+    mad_stream_init(&stream);
+    mad_stream_options(&stream, MAD_OPTION_IGNORECRC);
+    mad_synth_init(&synth);
+
+    if(!info->playback){
+        AUDDBG("decode: playback == NULL\n");
+        return NULL;
+    }
+
+    AUDDBG("decode: fmt = %d freq = %d channels = %d\n", info->fmt, info->freq, info->channels);
+
+    if(check_audio_param(info) == FALSE)
+        return NULL;
+
+    if (!info->playback->output->open_audio(info->fmt, info->freq, info->channels)) {
+        g_mutex_lock(pb_mutex);
+        info->playback->error = TRUE;
+        info->playback->eof = 1;
+        g_mutex_unlock(pb_mutex);        
+        g_message("failed to open audio output: %s",
+                  info->playback->output->description);
+        return NULL;
+    }
+
+    /* set mainwin title */
+    if (info->title)
+        g_free(info->title);
+    info->title = aud_tuple_formatter_make_title_string(info->tuple, audmad_config->title_override == TRUE ?
+                                       audmad_config->id3_format : aud_get_gentitle_format());
+
+    tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS),
+        info->playback->set_params(info->playback, info->title,
+                             (tlen == 0 || info->size <= 0) ? -1 : tlen,
+                             info->bitrate, info->freq, info->channels);
+
+    AUDDBG("decode: tlen = %d\n", tlen);
+
+    /* main loop */
+    do {
+        if (!info->playback->playing) {
+            AUDDBG("decode: stop signaled\n");
+            break;
+        }
+        if (seek_skip)
+            remainder = 0;
+        else {
+            remainder = stream.bufend - stream.next_frame;
+            memcpy(buffer, stream.this_frame, remainder);
+        }
+        len = input_get_data(info, buffer + remainder,
+                             BUFFER_SIZE - remainder);
+
+        input_process_remote_metadata(info);
+
+        if (len <= 0) {
+            AUDDBG("finished decoding\n");
+            break;
+        }
+        len += remainder;
+        if (len < MAD_BUFFER_GUARD) {
+            int i;
+            for (i = len; i < MAD_BUFFER_GUARD; i++)
+                buffer[i] = 0;
+            len = MAD_BUFFER_GUARD;
+        }
+
+        mad_stream_buffer(&stream, buffer, len);
+
+        if (seek_skip) {
+
+            AUDDBG("skipping: %d\n", seek_skip);
+
+            int skip = 2;
+            do {
+                if (mad_frame_decode(&frame, &stream) == 0) {
+                    mad_timer_add(&info->pos, frame.header.duration);
+                    if (--skip == 0)
+                        mad_synth_frame(&synth, &frame);
+                }
+                else if (!MAD_RECOVERABLE(stream.error)) {
+                    g_mutex_lock(pb_mutex);
+                    info->playback->error = TRUE;
+                    info->playback->eof = 1;
+                    g_mutex_unlock(pb_mutex);
+                    break;
+                }
+            }
+            while (skip);
+            seek_skip = FALSE;
+        }
+
+        while (info->playback->playing) {
+            if (info->seek != -1 && info->size > 0) {
+
+                AUDDBG("seeking: %ld\n", info->seek);
+
+                int new_position;
+                gulong milliseconds =
+                    mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS);
+                if (info->seek >= milliseconds)
+                    info->seek = milliseconds;
+
+                mad_timer_set(&info->pos, 0, info->seek, 1000); // in millisecond
+                new_position =
+                    ((double) info->seek / (double) milliseconds) * info->size;
+
+                if(new_position < 0)
+                    new_position = 0;
+
+                AUDDBG("seeking to: %d bytes\n", new_position);
+
+                if (aud_vfs_fseek(info->infile, new_position, SEEK_SET) == -1)
+                    audmad_error("failed to seek to: %d", new_position);
+                mad_frame_mute(&frame);
+                mad_synth_mute(&synth);
+                stream.error = MAD_ERROR_BUFLEN;
+                info->playback->output->flush(mad_timer_count(info->pos, MAD_UNITS_MILLISECONDS));
+                stream.sync = 0;
+                info->seek = -1;
+                seek_skip = TRUE;
+                break;
+            }
+
+            if (mad_header_decode(&frame.header, &stream) == -1) {
+                if (!MAD_RECOVERABLE(stream.error)) {
+                    break;
+                }
+                if (stream.error == MAD_ERROR_LOSTSYNC) {
+                    /* ignore LOSTSYNC due to ID3 tags */
+                    int tagsize = id3_tag_query(stream.this_frame,
+                                                stream.bufend -
+                                                stream.this_frame);
+                    if (tagsize > 0) {
+                        mad_stream_skip(&stream, tagsize);
+                        continue;
+                    }
+                }
+
+                AUDDBG("(recovered) error decoding header %d: %s\n",
+                          info->current_frame,
+                          mad_stream_errorstr(&stream));
+
+                continue;
+            }
+
+            info->bitrate = frame.header.bitrate;
+
+            if (!audmad_config->show_avg_vbr_bitrate && info->vbr && (iteration % 40 == 0)) {
+
+#ifdef DEBUG_INTENSIVELY
+                AUDDBG("decode vbr tlen = %d\n", tlen);
+#endif
+                info->playback->set_params(info->playback, info->title,
+                                     (tlen == 0 || info->size <= 0) ? -1 : tlen,
+                                     info->bitrate, info->freq, info->channels);
+            }
+            iteration++;
+
+            if (mad_frame_decode(&frame, &stream) == -1) {
+                if (!MAD_RECOVERABLE(stream.error))
+                    break;
+
+                AUDDBG("(recovered) error decoding frame %d: %s\n",
+                          info->current_frame,
+                          mad_stream_errorstr(&stream));
+
+            }
+
+            info->current_frame++;
+
+            if (info->freq != frame.header.samplerate
+                || info->channels !=
+                (guint) MAD_NCHANNELS(&frame.header)) {
+
+                AUDDBG("change in audio type detected\n");
+                AUDDBG("old: frequency = %d, channels = %d\n", info->freq,
+                          info->channels);
+                AUDDBG("new: frequency = %d, channels = %d\n",
+                          frame.header.samplerate,
+                          (guint) MAD_NCHANNELS(&frame.header));
+
+                info->freq = frame.header.samplerate;
+                info->channels = MAD_NCHANNELS(&frame.header);
+
+                if(audmad_config->force_reopen_audio && check_audio_param(info)) {
+                    gint current_time = info->playback->output->output_time();
+
+                    AUDDBG("re-opening audio due to change in audio type\n");
+
+                    info->playback->output->close_audio();
+                    if (!info->playback->output->open_audio(info->fmt, info->freq,
+                                                            info->channels)) {
+                        g_mutex_lock(pb_mutex);
+                        info->playback->error = TRUE;
+                        info->playback->eof = 1;
+                        g_mutex_unlock(pb_mutex);
+                        g_message("failed to re-open audio output: %s",
+                                  info->playback->output->description);
+                        return NULL;
+                    }
+                    // restore time and advance 0.5sec
+                    info->seek = current_time + 500;
+                }
+            }
+
+            if (!info->playback->playing)
+                break;
+            mad_synth_frame(&synth, &frame);
+            mad_stream_sync(&stream);
+
+            write_output(info, &synth.pcm, &frame.header);
+            mad_timer_add(&info->pos, frame.header.duration);
+        }
+    }
+    while (stream.error == MAD_ERROR_BUFLEN);
+
+    /* free mad stuff */
+    mad_frame_finish(&frame);
+    mad_stream_finish(&stream);
+    mad_synth_finish(&synth);
+
+    if (info->playback->playing) {
+        GTimeVal sleeptime;
+
+        info->playback->output->buffer_free();
+        info->playback->output->buffer_free();
+        while (info->playback->output->buffer_playing()) {
+
+            AUDDBG("f: buffer_playing=%d\n", info->playback->output->buffer_playing());
+
+            g_get_current_time(&sleeptime);
+            g_time_val_add(&sleeptime, 500000);
+            
+            g_mutex_lock(mad_mutex);
+            g_cond_timed_wait(mad_cond, mad_mutex, &sleeptime);
+            g_mutex_unlock(mad_mutex);
+            if (!info->playback->playing) {
+                break;
+            }
+
+        }
+    }
+
+    AUDDBG("e: decode\n");
+
+    aud_tuple_free(info->tuple);
+    info->tuple = NULL;
+
+    info->playback->output->close_audio();
+    g_mutex_lock(mad_mutex);
+    info->playback->playing = 0;
+    g_mutex_unlock(mad_mutex);
+    return NULL; /* dummy */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/dither.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <assert.h>
+#include "../../config.h"
+
+#define MEXP 19937
+
+#ifdef HAVE_SSE2
+#define SSE2 1
+#endif
+#ifdef HAVE_ALTIVEC
+#define ALTIVEC 1
+#endif
+
+#include "SFMT.h"
+#include "SFMT.c"
+
+int
+triangular_dither_noise(int nbits)
+{
+    // parameter nbits : the peak-to-peak amplitude desired (in bits)
+    //  use with nbits set to    2 + nber of bits to be trimmed.
+    // (because triangular is made from two uniformly distributed processes,
+    // it starts at 2 bits peak-to-peak amplitude)
+    // see The Theory of Dithered Quantization by Robert Alexander Wannamaker
+    // for complete proof of why that's optimal
+
+    int v = (gen_rand32() / 2 - gen_rand32() / 2);   // in ]-2^31, 2^31[
+    //int signe = (v>0) ? 1 : -1;
+    int P = 1 << (32 - nbits); // the power of 2
+    v /= P;
+    // now v in ]-2^(nbits-1), 2^(nbits-1) [ 
+
+    return v;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/input.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,626 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif                          /* HAVE_ASSERT_H */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif                          /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif                          /* HAVE_SYS_SOCKET_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif                          /* HAVE_NETINET_IN_H */
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif                          /* HAVE_ARPA_INET_H */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif                          /* HAVE_NETDB_H */
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif                          /* HAVE_SYS_STAT_H */
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif                          /* HAVE_SYS_TIME_H */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <audacious/util.h>
+
+#include "input.h"
+#include "replaygain.h"
+
+#define DIR_SEPARATOR '/'
+#define HEADER_SIZE 256
+#define LINE_LENGTH 256
+
+extern gboolean scan_file(struct mad_info_t *info, gboolean fast);
+
+/**
+ * init the mad_info_t struct.
+ */
+gboolean
+input_init(struct mad_info_t * info, const char *url, VFSFile *fd)
+{
+    AUDDBG("f: input_init\n");
+
+    memset(info, 0, sizeof(struct mad_info_t)); // all fields are cleared to 0 --yaz
+
+    info->fmt = FMT_S16_LE;
+    info->channels = -1;
+    info->mpeg_layer = -1;
+    info->size = -1;
+    info->freq = -1;
+    info->seek = -1;
+    info->duration = mad_timer_zero;
+    info->pos = mad_timer_zero;
+    info->url = g_strdup(url);
+    info->filename = g_strdup(url);
+
+    // from input_read_replaygain()
+    info->replaygain_album_scale = -1;
+    info->replaygain_track_scale = -1;
+    info->mp3gain_undo = -77;
+    info->mp3gain_minmax = -77;
+
+    if(!fd){
+        info->infile = aud_vfs_fopen(info->filename, "rb");
+        if (info->infile == NULL) {
+            return FALSE;
+        }
+    }
+    else{
+        AUDDBG("input_init: aud_vfs_dup\n");
+
+        info->infile = aud_vfs_dup(fd);
+    }
+
+    // obtain file size
+    info->size = aud_vfs_fsize(info->infile);
+    info->remote = info->size == 0 ? TRUE : FALSE; //proxy connection may result in non-zero size.
+    if(aud_vfs_is_remote((gchar *)url))
+        info->remote = TRUE;
+
+    info->fileinfo_request = FALSE;
+
+    AUDDBG("i: info->size = %lu\n", (long unsigned int)info->size);
+    AUDDBG("e: input_init\n");
+
+    return TRUE;
+}
+
+/* return length in letters */
+size_t
+mad_ucs4len(id3_ucs4_t *ucs)
+{
+    id3_ucs4_t *ptr = ucs;
+    size_t len = 0;
+
+    while(*ptr++ != 0)
+        len++;
+
+    return len;
+}
+
+/* duplicate id3_ucs4_t string. new string will be terminated with 0. */
+id3_ucs4_t *
+mad_ucs4dup(id3_ucs4_t *org)
+{
+    id3_ucs4_t *new = NULL;
+    size_t len = mad_ucs4len(org);
+
+    new = g_malloc0((len + 1) * sizeof(id3_ucs4_t));
+    memcpy(new, org, len * sizeof(id3_ucs4_t));
+    *(new + len) = 0; //terminate
+
+    return new;
+}
+
+#define BYTES(x) ((x) * sizeof(id3_ucs4_t))
+
+id3_ucs4_t *
+mad_parse_genre(const id3_ucs4_t *string)
+{
+    id3_ucs4_t *ret = NULL;
+    id3_ucs4_t *tmp = NULL;
+    id3_ucs4_t *genre = NULL;
+    id3_ucs4_t *ptr, *end, *tail, *tp;
+    size_t ret_len = 0; //num of ucs4 char!
+    size_t tmp_len = 0;
+    size_t string_len = 0;
+    gboolean is_num = TRUE;
+
+    if(!string)
+        return NULL;
+
+    string_len = mad_ucs4len((id3_ucs4_t *)string);
+    tail = (id3_ucs4_t *)string + string_len;
+
+    if(BYTES(string_len + 1) > 1024) {
+        ret = g_malloc0(BYTES(string_len + 1));
+    }
+    else {
+        ret = g_malloc0(1024);
+    }
+
+    for(ptr = (id3_ucs4_t *)string; ptr <= tail && *ptr != 0; ptr++) {
+        if(*ptr == '(') {
+            if(ptr < tail && *(++ptr) == '(') { // escaped text like: ((something)
+                for(end = ptr; *end != ')' && *end != 0;) { // copy "(something)"
+                    end++;
+                }
+                end++; //include trailing ')'
+                memcpy(ret, ptr, BYTES(end - ptr));
+                ret_len += (end - ptr);
+                *(ret + ret_len) = 0; //terminate
+                ptr = end + 1;
+            }
+            else if (ptr <= tail && *ptr != 0) {
+                // reference to an id3v1 genre code
+                for(end = ptr; *end != ')' && *end != 0;) {
+                    end++;
+                }
+
+                tmp = g_malloc0(BYTES(end - ptr + 1));
+                memcpy(tmp, ptr, BYTES(end - ptr));
+                *(tmp + (end - ptr)) = 0; //terminate
+                ptr += end - ptr;
+
+                genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp);
+
+                g_free(tmp);
+                tmp = NULL;
+
+                tmp_len = mad_ucs4len(genre);
+
+                memcpy(ret + ret_len, genre, BYTES(tmp_len));
+
+                ret_len += tmp_len;
+                *(ret + ret_len) = 0; //terminate
+            }
+        }
+        else {
+            for(end = ptr; *end != '(' && *end != 0; ) {
+                end++;
+            }
+            // scan string to determine whether a genre code number or not
+            tp = ptr;
+            is_num = TRUE;
+            while(tp < end) {
+                if(*tp < '0' || *tp > '9') { // anything else than number appears.
+                    is_num = FALSE;
+                    break;
+                }
+                tp++;
+            }
+
+            if(is_num) {
+                AUDDBG("is_num!\n");
+
+                tmp = g_malloc0(BYTES(end - ptr + 1));
+                memcpy(tmp, ptr, BYTES(end - ptr));
+                *(tmp + (end - ptr)) = 0; //terminate
+                ptr += end - ptr;
+
+                genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp);
+                AUDDBG("genre length = %d\n", mad_ucs4len(genre));
+
+                g_free(tmp);
+                tmp = NULL;
+
+                tmp_len = mad_ucs4len(genre);
+
+                memcpy(ret + ret_len, genre, BYTES(tmp_len));
+
+                ret_len += tmp_len;
+                *(ret + ret_len) = 0; //terminate
+            }
+            else { // plain text
+                AUDDBG("plain!\n");
+                AUDDBG("ret_len = %d\n", ret_len);
+                AUDDBG("end - ptr = %d\n", BYTES(end - ptr));
+
+                memcpy(ret + ret_len, ptr, BYTES(end - ptr));
+                ret_len = ret_len + (end - ptr);
+                *(ret + ret_len) = 0; //terminate
+                ptr += (end - ptr);
+            }
+        }
+    }
+    return ret;
+}
+
+gchar *
+input_id3_get_string(struct id3_tag * tag, const gchar *frame_name)
+{
+    gchar *rtn0 = NULL, *rtn = NULL;
+    const id3_ucs4_t *string_const = NULL;
+    id3_ucs4_t *string = NULL;
+    struct id3_frame *frame;
+    union id3_field *field;
+    int encoding = -1;
+
+    frame = id3_tag_findframe(tag, frame_name, 0);
+    if (!frame)
+        return NULL;
+
+    field = id3_frame_field(frame, 0);
+    encoding = id3_field_gettextencoding(field);
+
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT))
+        field = id3_frame_field(frame, 3);
+    else
+        field = id3_frame_field(frame, 1);
+
+    if (!field)
+        return NULL;
+
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT))
+        string_const = id3_field_getfullstring(field);
+    else
+        string_const = id3_field_getstrings(field, 0);
+
+    if (!string_const)
+        return NULL;
+
+    if (!strcmp(frame_name, ID3_FRAME_GENRE)) {
+        string = mad_parse_genre(string_const);
+    }
+    else {
+        string = mad_ucs4dup((id3_ucs4_t *)string_const);
+    }
+
+    if (!string)
+        return NULL;
+
+    switch (encoding) {
+    case ID3_FIELD_TEXTENCODING_ISO_8859_1:
+        rtn0 = (gchar *)id3_ucs4_latin1duplicate(string);
+        rtn = aud_str_to_utf8(rtn0);
+        g_free(rtn0);
+        break;
+    case ID3_FIELD_TEXTENCODING_UTF_8:
+    default:
+        rtn = (gchar *)id3_ucs4_utf8duplicate(string);
+        break;
+    }
+    g_free((void *)string);
+        
+    AUDDBG("i: string = %s\n", rtn);
+
+    return rtn;
+}
+
+static void
+input_set_and_free_tag(struct id3_tag *tag, Tuple *tuple, const gchar *frame, const gint nfield)
+{
+    gchar *scratch = input_id3_get_string(tag, frame);
+
+    aud_tuple_associate_string(tuple, nfield, NULL, scratch);
+    aud_tuple_associate_string(tuple, -1, frame, scratch);
+
+    g_free(scratch);
+}
+
+static void
+input_alloc_tag(struct mad_info_t *info)
+{
+    Tuple *tuple;
+
+    if (info->tuple == NULL) {
+        tuple = aud_tuple_new();
+        info->tuple = tuple;
+        aud_tuple_associate_int(info->tuple, FIELD_LENGTH, NULL, -1);
+    }
+}
+
+/**
+ * read the ID3 tag 
+ */
+static void
+input_read_tag(struct mad_info_t *info)
+{
+    gchar *string = NULL;
+    Tuple *tuple;
+    glong curpos = 0;
+
+    AUDDBG("f: input_read_tag\n");
+
+    if (info->tuple != NULL)
+        aud_tuple_free(info->tuple);
+        
+    tuple = aud_tuple_new_from_filename(info->filename);
+    info->tuple = tuple;
+
+    if(info->infile) {
+        curpos = aud_vfs_ftell(info->infile);
+        info->id3file = id3_file_vfsopen(info->infile, ID3_FILE_MODE_READONLY);
+    }
+    else {
+        info->id3file = id3_file_open(info->filename, ID3_FILE_MODE_READONLY);
+    }
+
+    if (!info->id3file) {
+        AUDDBG("read_tag: no id3file\n");
+        return;
+    }
+
+    info->tag = id3_file_tag(info->id3file);
+    if (!info->tag) {
+        AUDDBG("read_tag: no tag\n");
+        return;
+    }
+
+    input_set_and_free_tag(info->tag, tuple, ID3_FRAME_ARTIST, FIELD_ARTIST);
+    input_set_and_free_tag(info->tag, tuple, ID3_FRAME_TITLE, FIELD_TITLE);
+    input_set_and_free_tag(info->tag, tuple, ID3_FRAME_ALBUM, FIELD_ALBUM);
+    input_set_and_free_tag(info->tag, tuple, ID3_FRAME_GENRE, FIELD_GENRE);
+    input_set_and_free_tag(info->tag, tuple, ID3_FRAME_COMMENT, FIELD_COMMENT);
+
+    string = input_id3_get_string(info->tag, ID3_FRAME_TRACK);
+    if (string) {
+        aud_tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, atoi(string));
+        g_free(string);
+        string = NULL;
+    }
+
+    // year
+    string = NULL;
+    string = input_id3_get_string(info->tag, ID3_FRAME_YEAR);   //TDRC
+    if (!string)
+        string = input_id3_get_string(info->tag, "TYER");
+
+    if (string) {
+        aud_tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(string));
+        g_free(string);
+        string = NULL;
+    }
+
+    // length
+    string = input_id3_get_string(info->tag, "TLEN");
+    if (string && atoi(string)) {
+        aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, atoi(string));
+        AUDDBG("input_read_tag: TLEN = %d\n", atoi(string));
+        g_free(string);
+        string = NULL;
+    } else
+        aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1);
+    
+    aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, "MPEG Audio (MP3)");
+    aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, "lossy");
+
+    info->title = aud_tuple_formatter_make_title_string(tuple, audmad_config->title_override == TRUE ?
+        audmad_config->id3_format : aud_get_gentitle_format());
+
+    // for connection via proxy, we have to stop transfer once. I can't explain the reason.
+    if (info->infile != NULL) {
+        aud_vfs_fseek(info->infile, -1, SEEK_SET); // an impossible request
+        aud_vfs_fseek(info->infile, curpos, SEEK_SET);
+    }
+    
+    AUDDBG("e: input_read_tag\n");
+}
+
+void
+input_process_remote_metadata(struct mad_info_t *info)
+{
+    gboolean metadata = FALSE;
+
+    if(info->remote && mad_timer_count(info->duration, MAD_UNITS_SECONDS) <= 0){
+        gchar *tmp = NULL;
+
+#ifdef DEBUG_INTENSIVELY
+        AUDDBG("process_remote_meta\n");
+#endif
+        g_free(info->title);
+        info->title = NULL;
+        aud_tuple_disassociate(info->tuple, FIELD_TITLE, NULL);
+        aud_tuple_disassociate(info->tuple, FIELD_ALBUM, NULL);
+
+        tmp = aud_vfs_get_metadata(info->infile, "track-name");
+        if(tmp){
+            metadata = TRUE;
+            gchar *scratch;
+
+            scratch = aud_str_to_utf8(tmp);
+            aud_tuple_associate_string(info->tuple, FIELD_TITLE, NULL, scratch);
+            g_free(scratch);
+
+            g_free(tmp);
+            tmp = NULL;
+        }
+
+        tmp = aud_vfs_get_metadata(info->infile, "stream-name");
+        if(tmp){
+            metadata = TRUE;
+            gchar *scratch;
+
+            scratch = aud_str_to_utf8(tmp);
+            aud_tuple_associate_string(info->tuple, FIELD_ALBUM, NULL, scratch);
+            aud_tuple_associate_string(info->tuple, -1, "stream", scratch);
+            g_free(scratch);
+
+            g_free(tmp);
+            tmp = NULL;
+        }
+
+        if (metadata)
+            tmp = aud_tuple_formatter_process_string(info->tuple, "${?title:${title}}${?stream: (${stream})}");
+        else {
+            gchar *realfn = g_filename_from_uri(info->filename, NULL, NULL);
+            gchar *tmp2 = g_path_get_basename(realfn ? realfn : info->filename); // info->filename is uri. --yaz
+            tmp = aud_str_to_utf8(tmp2);
+            g_free(tmp2); tmp2 = NULL;
+            g_free(realfn); realfn = NULL;
+//            tmp = g_strdup(g_basename(info->filename)); //XXX maybe ok. --yaz
+        }
+
+        /* call set_info only if tmp is different from prev_tmp */
+        if ( ( ( info->prev_title != NULL ) && ( strcmp(info->prev_title,tmp) ) ) ||
+             ( info->prev_title == NULL ) )
+        {
+            info->playback->set_params(info->playback, tmp,
+                                 -1, // indicate the stream is unseekable
+                                 info->bitrate, info->freq, info->channels);
+            if (info->prev_title)
+                g_free(info->prev_title);
+            info->prev_title = g_strdup(tmp);
+        }
+
+        g_free(tmp);
+    }
+}
+
+
+/**
+ * Retrieve meta-information about URL.
+ * For local files this means ID3 tag etc.
+ */
+gboolean
+input_get_info(struct mad_info_t *info, gboolean fast_scan)
+{
+#ifdef AUD_DEBUG
+    gchar *tmp = g_filename_to_utf8(info->filename, -1, NULL, NULL, NULL);    
+    AUDDBG("f: input_get_info: %s, fast_scan = %s\n", tmp, fast_scan ? "TRUE" : "FALSE");
+    g_free(tmp);
+#endif                          /* DEBUG */
+
+    input_alloc_tag(info);
+    input_read_tag(info);
+
+    if(!info->remote) { // reduce startup delay
+        read_replaygain(info);
+    }
+
+    /* scan mp3 file, decoding headers */
+    if (scan_file(info, fast_scan) == FALSE) {
+        AUDDBG("input_get_info: scan_file failed\n");
+        return FALSE;
+    }
+
+    /* reset the input file to the start */
+    aud_vfs_fseek(info->infile, 0, SEEK_SET);
+    info->offset = 0;
+
+    /* use the filename for the title as a last resort */
+    if (!info->title) {
+        char *pos = strrchr(info->filename, DIR_SEPARATOR); //XXX info->filename is uri. --yaz
+        if (pos)
+            info->title = g_strdup(pos + 1);
+        else
+            info->title = g_strdup(info->filename); //XXX info->filename is uri. --yaz
+    }
+
+    AUDDBG("e: input_get_info\n");
+    return TRUE;
+}
+
+
+
+/**
+ * Read data from the source given my madinfo into the buffer
+ * provided.  Return the number of bytes read.
+ * @return 0 on EOF
+ * @return -1 on error
+ */
+// this function may be called before info->playback initialized.
+int
+input_get_data(struct mad_info_t *info, guchar * buffer,
+               int buffer_size)
+{
+    int len = 0;
+#ifdef DEBUG_INTENSIVELY
+  AUDDBG ("f: input_get_data: %d\n", buffer_size);
+#endif
+    /* simply read to data from the file */
+    len = aud_vfs_fread(buffer, 1, buffer_size, info->infile); //aud_vfs_fread returns num of elements.
+
+    if(len == 0 && info->playback){
+        info->playback->eof = TRUE;
+    }
+
+#ifdef DEBUG_INTENSIVELY
+    AUDDBG ("e: input_get_data: size=%d offset=%d\n", len, info->offset);
+#endif
+
+    info->offset += len;
+    return len;
+}
+
+/**
+ * Free up all mad_info_t related resourses.
+ */
+gboolean
+input_term(struct mad_info_t * info)
+{
+    AUDDBG("f: input_term\n");
+
+    if (info->title)
+        g_free(info->title);
+    if (info->url)
+        g_free(info->url);
+    if (info->filename)
+        g_free(info->filename);
+    if (info->infile)
+        aud_vfs_fclose(info->infile);
+    if (info->id3file)
+        id3_file_close(info->id3file);
+
+    if (info->replaygain_album_str)
+        g_free(info->replaygain_album_str);
+    if (info->replaygain_track_str)
+        g_free(info->replaygain_track_str);
+    if (info->replaygain_album_peak_str)
+        g_free(info->replaygain_album_peak_str);
+    if (info->replaygain_track_peak_str)
+        g_free(info->replaygain_track_peak_str);
+    if (info->mp3gain_undo_str)
+        g_free(info->mp3gain_undo_str);
+    if (info->mp3gain_minmax_str)
+        g_free(info->mp3gain_minmax_str);
+
+    if (info->tuple) {
+        aud_tuple_free(info->tuple);
+        info->tuple = NULL;
+    }
+
+    if (info->prev_title)
+        g_free(info->prev_title);
+
+    /* set everything to zero in case it gets used again. */
+    memset(info, 0, sizeof(struct mad_info_t));
+
+    AUDDBG("e: input_term\n");
+
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/input.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,33 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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 INPUT_H
+#define INPUT_H
+
+#include "plugin.h"
+gboolean input_init(struct mad_info_t *songinfo, const gchar * url, VFSFile *fd);
+gboolean input_term(struct mad_info_t *songinfo);
+gboolean input_get_info(struct mad_info_t *songinfo, gboolean fast_scan);
+gint input_get_data(struct mad_info_t *songinfo, guchar * buffer,
+                    gint buffer_size);
+gchar *input_id3_get_string(struct id3_tag *tag, const gchar *frame_name);
+
+#endif                          /* ! INPUT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/plugin.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,839 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+/* #define AUD_DEBUG 1 */
+
+#include "config.h"
+#include "plugin.h"
+#include "input.h"
+
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <audacious/util.h>
+#include <audacious/configdb.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <audacious/vfs.h>
+#include <sys/stat.h>
+#include "SFMT.h"
+#include "tuple.h"
+
+/*
+ * Global variables
+ */
+audmad_config_t *audmad_config;   /**< global configuration */
+GMutex *mad_mutex;
+GMutex *pb_mutex;
+GCond *mad_cond;
+
+/*
+ * static variables
+ */
+static GThread *decode_thread; /**< the single decoder thread */
+static struct mad_info_t info;   /**< info for current track */
+
+#ifndef NOGUI
+static GtkWidget *error_dialog = 0;
+#endif
+
+extern gboolean scan_file(struct mad_info_t *info, gboolean fast);
+
+static gint mp3_bitrate_table[5][16] = {
+  { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 L1 */
+  { 0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 L2 */
+  { 0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 L3 */
+  { 0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2(.5) L1 */
+  { 0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, -1 }  /* MPEG2(.5) L2,L3 */
+};
+
+static gint mp3_samplerate_table[4][4] = {
+  { 11025, 12000, 8000, -1 },   /* MPEG2.5 */
+  { -1, -1, -1, -1 },           /* Reserved */
+  { 22050, 24000, 16000, -1 },  /* MPEG2 */
+  { 44100, 48000, 32000, -1 }   /* MPEG1 */
+};
+
+/*
+ * Function extname (filename)
+ *
+ *    Return pointer within filename to its extenstion, or NULL if
+ *    filename has no extension.
+ *
+ */
+static gchar *
+extname(const char *filename)
+{
+    gchar *ext = strrchr(filename, '.');
+
+    if (ext != NULL)
+        ++ext;
+
+    return ext;
+}
+
+
+void
+audmad_config_compute(audmad_config_t *config)
+{
+    /* set some config parameters by parsing text fields
+       (RG default gain, etc..)
+     */
+    const gchar *text;
+    gdouble x;
+
+    text = config->replaygain.preamp0_db;
+    if ( text != NULL )
+      x = g_strtod(text, NULL);
+    else
+      x = 0;
+    config->replaygain.preamp0_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp0=[%s] -> %g  -> %g\n", text, x, config->preamp0_scale);
+
+    text = config->replaygain.preamp1_db;
+    if ( text != NULL )
+      x = g_strtod(text, NULL);
+    else
+      x = 0;
+    config->replaygain.preamp1_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp1=[%s] -> %g  -> %g\n", text, x,
+              config->replaygain.preamp1_scale);
+
+    text = config->replaygain.preamp2_db;
+    if ( text != NULL )
+      x = g_strtod(text, NULL);
+    else
+      x = 0;
+    config->replaygain.preamp2_scale = (x != 0) ? pow(10.0, x / 20) : 1;
+    AUDDBG("RG.preamp2=[%s] -> %g  -> %g\n", text, x,
+              config->replaygain.preamp2_scale);
+}
+
+static void
+audmad_init()
+{
+    ConfigDb *db = NULL;
+
+    audmad_config = g_malloc0(sizeof(audmad_config_t));
+
+    audmad_config->dither = TRUE;
+    audmad_config->force_reopen_audio = FALSE;
+    audmad_config->fast_play_time_calc = TRUE;
+    audmad_config->use_xing = TRUE;
+    audmad_config->sjis = FALSE;
+    audmad_config->show_avg_vbr_bitrate = TRUE;
+    audmad_config->replaygain.enable = TRUE;
+    audmad_config->replaygain.track_mode = FALSE;
+    audmad_config->replaygain.anti_clip = FALSE;
+    audmad_config->replaygain.adaptive_scaler = FALSE;
+    audmad_config->title_override = FALSE;
+
+
+    db = aud_cfg_db_open();
+    if (db) {
+        //audio
+        aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config->dither);
+        aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio",
+                            &audmad_config->force_reopen_audio);
+
+        //metadata
+        aud_cfg_db_get_bool(db, "MAD", "fast_play_time_calc",
+                            &audmad_config->fast_play_time_calc);
+        aud_cfg_db_get_bool(db, "MAD", "use_xing",
+                            &audmad_config->use_xing);
+        aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config->sjis);
+
+        //misc
+        aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate",
+                            &audmad_config->show_avg_vbr_bitrate);
+
+        //gain control
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp0_db",
+                              &audmad_config->replaygain.preamp0_db);
+        aud_cfg_db_get_bool(db, "MAD", "RG.enable",
+                            &audmad_config->replaygain.enable);
+        aud_cfg_db_get_bool(db, "MAD", "RG.track_mode",
+                            &audmad_config->replaygain.track_mode);
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp1_db",
+                              &audmad_config->replaygain.preamp1_db);
+        aud_cfg_db_get_string(db, "MAD", "RG.preamp2_db",
+                              &audmad_config->replaygain.preamp2_db);
+        aud_cfg_db_get_bool(db, "MAD", "RG.anti_clip",
+                            &audmad_config->replaygain.anti_clip);
+        aud_cfg_db_get_bool(db, "MAD", "RG.adaptive_scaler",
+                            &audmad_config->replaygain.adaptive_scaler);
+
+        //text
+        aud_cfg_db_get_bool(db, "MAD", "title_override",
+                            &audmad_config->title_override);
+        aud_cfg_db_get_string(db, "MAD", "id3_format",
+                              &audmad_config->id3_format);
+
+        aud_cfg_db_close(db);
+    }
+
+    mad_mutex = g_mutex_new();
+    pb_mutex = g_mutex_new();
+    mad_cond = g_cond_new();
+    audmad_config_compute(audmad_config);
+
+    if (!audmad_config->replaygain.preamp0_db)
+        audmad_config->replaygain.preamp0_db = g_strdup("+0.00");
+
+    if (!audmad_config->replaygain.preamp1_db)
+        audmad_config->replaygain.preamp1_db = g_strdup("+6.00");
+    if (!audmad_config->replaygain.preamp2_db)
+        audmad_config->replaygain.preamp2_db = g_strdup("+0.00");
+
+    if (!audmad_config->id3_format)
+        audmad_config->id3_format = g_strdup("(none)");
+
+    init_gen_rand(4357);
+
+    aud_mime_set_plugin("audio/mpeg", mad_plugin);
+}
+
+static void
+audmad_cleanup()
+{
+    g_free(audmad_config->replaygain.preamp0_db);
+    g_free(audmad_config->replaygain.preamp1_db);
+    g_free(audmad_config->replaygain.preamp2_db);
+    g_free(audmad_config->id3_format);
+    g_free(audmad_config);
+    
+    g_cond_free(mad_cond);
+    g_mutex_free(mad_mutex);
+    g_mutex_free(pb_mutex);
+}
+
+static gboolean
+mp3_head_check(guint32 head, gint *frameSize)
+{
+    gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding;
+
+    /* http://www.mp3-tech.org/programmer/frame_header.html
+     * Bits 21-31 must be set (frame sync)
+     */
+    if ((head & 0xffe00000) != 0xffe00000)
+        return FALSE;
+
+    /* check if layer bits (17-18) are good */
+    layer = (head >> 17) & 0x3;
+    if (!layer)
+        return FALSE; /* 00 = reserved */
+    layer = 4 - layer;
+
+    /* check if bitrate index bits (12-15) are acceptable */
+    bitIndex = (head >> 12) & 0xf;
+
+    /* 1111 and 0000 are reserved values for all layers */
+    if (bitIndex == 0xf || bitIndex == 0)
+        return FALSE;
+
+    /* check samplerate index bits (10-11) */
+    sampleIndex = (head >> 10) & 0x3;
+    if (sampleIndex == 0x3)
+        return FALSE;
+
+    /* check version bits (19-20) and get bitRate */
+    version = (head >> 19) & 0x03;
+    switch (version) {
+        case 0: /* 00 = MPEG Version 2.5 */
+        case 2: /* 10 = MPEG Version 2 */
+            if (layer == 1)
+                bitRate = mp3_bitrate_table[3][bitIndex];
+            else
+                bitRate = mp3_bitrate_table[4][bitIndex];
+            break;
+
+        case 1: /* 01 = reserved */
+            return FALSE;
+
+        case 3: /* 11 = MPEG Version 1 */
+            bitRate = mp3_bitrate_table[layer][bitIndex];
+            break;
+
+        default:
+            return FALSE;
+    }
+
+    /* check layer II restrictions vs. bitrate */
+    if (layer == 2) {
+        gint chanMode = (head >> 6) & 0x3;
+
+        if (chanMode == 0x3) {
+            /* single channel with bitrate > 192 */
+            if (bitRate > 192)
+                return FALSE;
+        } else {
+            /* any other mode with bitrates 32-56 and 80.
+             * NOTICE! this check is not entirely correct, but I think
+             * it is sufficient in most cases.
+             */
+            if (((bitRate >= 32 && bitRate <= 56) || bitRate == 80))
+                return FALSE;
+        }
+    }
+
+    /* calculate approx. frame size */
+    padding = (head >> 9) & 1;
+    sampleRate = mp3_samplerate_table[version][sampleIndex];
+    if (layer == 1)
+        *frameSize = ((12 * bitRate * 1000 / sampleRate) + padding) * 4;
+    else
+        *frameSize = (144 * bitRate * 1000) / (sampleRate + padding);
+
+    /* check if bits 16 - 19 are all set (MPEG 1 Layer I, not protected?) */
+    if (((head >> 19) & 1) == 1 &&
+        ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1)
+        return FALSE;
+
+    /* not sure why we check this, but ok! */
+    if ((head & 0xffff0000) == 0xfffe0000)
+        return FALSE;
+
+    return TRUE;
+}
+
+static int
+mp3_head_convert(const guchar * hbuf)
+{
+    return ((unsigned long) hbuf[0] << 24) |
+        ((unsigned long) hbuf[1] << 16) |
+        ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3];
+}
+
+// audacious vfs fast version
+static int
+audmad_is_our_fd(char *filename, VFSFile *fin)
+{
+    guint32 check;
+    gchar *ext = extname(filename);
+    gint cyc = 0, chkcount = 0, chksize = 4096;
+    guchar buf[4];
+    guchar tmp[4096];
+    gint ret, i, frameSize;
+
+    info.remote = aud_vfs_is_remote(filename);
+
+    /* I've seen some flac files beginning with id3 frames..
+       so let's exclude known non-mp3 filename extensions */
+    if ((ext != NULL) &&
+        (!strcasecmp("flac", ext) || !strcasecmp("mpc", ext) ||
+         !strcasecmp("tta", ext)  || !strcasecmp("ogg", ext) ||
+         !strcasecmp("wma", ext) )
+        )
+        return 0;
+
+    if (fin == NULL) {
+        g_message("fin = NULL");
+        return 0;
+    }
+
+    if(aud_vfs_fread(buf, 1, 4, fin) == 0) {
+        gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
+        g_message("aud_vfs_fread failed @1 %s", tmp);
+        g_free(tmp);
+        return 0;
+    }
+
+    check = mp3_head_convert(buf);
+
+    if (memcmp(buf, "ID3", 3) == 0)
+        return 1;
+    else if (memcmp(buf, "OggS", 4) == 0)
+        return 0;
+    else if (memcmp(buf, "RIFF", 4) == 0)
+    {
+        aud_vfs_fseek(fin, 4, SEEK_CUR);
+        if(aud_vfs_fread(buf, 1, 4, fin) == 0) {
+            gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
+            g_message("aud_vfs_fread failed @2 %s", tmp);
+            g_free(tmp);
+            return 0;
+        }
+
+        if (memcmp(buf, "RMP3", 4) == 0)
+            return 1;
+    }
+
+    // check data for frame header
+    while (!mp3_head_check(check, &frameSize))
+    {
+        if((ret = aud_vfs_fread(tmp, 1, chksize, fin)) == 0){
+            gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
+            g_message("aud_vfs_fread failed @3 %s", tmp);
+            g_free(tmp);
+            return 0;
+        }
+        for (i = 0; i < ret; i++)
+        {
+            check <<= 8;
+            check |= tmp[i];
+
+            if (mp3_head_check(check, &frameSize)) {
+                /* when the first matching frame header is found, we check for
+                 * another frame by seeking to the approximate start of the
+                 * next header ... also reduce the check size.
+                 */
+                if (++chkcount >= 3) return 1;
+                aud_vfs_fseek(fin, frameSize-4, SEEK_CUR);
+                check = 0;
+                chksize = 8;
+            }
+        }
+
+        if (++cyc > 32)
+            return 0;
+    }
+
+    return 1;
+}
+
+// audacious vfs version
+static int
+audmad_is_our_file(char *filename)
+{
+    VFSFile *fin = NULL;
+    gint rtn;
+
+    fin = aud_vfs_fopen(filename, "rb");
+
+    if (fin == NULL)
+        return 0;
+
+    rtn = audmad_is_our_fd(filename, fin);
+    aud_vfs_fclose(fin);
+
+    return rtn;
+}
+
+static void
+audmad_stop(InputPlayback *playback)
+{
+    AUDDBG("f: audmad_stop\n");
+    g_mutex_lock(mad_mutex);
+    info.playback = playback;
+    g_mutex_unlock(mad_mutex);
+
+    if (decode_thread) {
+
+        g_mutex_lock(mad_mutex);
+        info.playback->playing = 0;
+        g_mutex_unlock(mad_mutex);
+        g_cond_signal(mad_cond);
+
+        AUDDBG("waiting for thread\n");
+        g_thread_join(decode_thread);
+        AUDDBG("thread done\n");
+
+        input_term(&info);
+        decode_thread = NULL;
+
+    }
+    AUDDBG("e: audmad_stop\n");
+}
+
+static void
+audmad_play_file(InputPlayback *playback)
+{
+    gboolean rtn;
+    gchar *url = playback->filename;
+
+#ifdef AUD_DEBUG
+    {
+        gchar *tmp = g_filename_to_utf8(url, -1, NULL, NULL, NULL);
+        AUDDBG("playing %s\n", tmp);
+        g_free(tmp);
+    }
+#endif                          /* DEBUG */
+
+    if (input_init(&info, url, NULL) == FALSE) {
+        g_message("error initialising input");
+        return;
+    }
+
+    // remote access must use fast scan.
+    rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config->fast_play_time_calc);
+
+    if (rtn == FALSE) {
+        g_message("error reading input info");
+        /*
+         * return;
+         * commenting this return seems to be a hacky fix for the damn lastfm plugin playback
+         * that used to work only for nenolod because of his fsck-ing lastfm subscription :p
+        */
+    }
+    g_mutex_lock(pb_mutex);
+    info.playback = playback;
+    info.playback->playing = 1;
+    g_mutex_unlock(pb_mutex);
+
+    decode_thread = g_thread_self();
+    playback->set_pb_ready(playback);
+    decode_loop(&info);
+}
+
+static void
+audmad_pause(InputPlayback *playback, short paused)
+{
+    g_mutex_lock(pb_mutex);
+    info.playback = playback;
+    g_mutex_unlock(pb_mutex);
+    playback->output->pause(paused);
+}
+
+static void
+audmad_mseek(InputPlayback *playback, gulong millisecond)
+{
+    g_mutex_lock(pb_mutex);
+    info.playback = playback;
+    info.seek = millisecond;
+    g_mutex_unlock(pb_mutex);
+}
+
+static void
+audmad_seek(InputPlayback *playback, gint time)
+{
+    audmad_mseek(playback, time * 1000);
+}
+
+/**
+ * Scan the given file or URL.
+ * Fills in the title string and the track length in milliseconds.
+ */
+static void
+audmad_get_song_info(char *url, char **title, int *length)
+{
+    struct mad_info_t myinfo;
+#ifdef AUD_DEBUG
+    gchar *tmp = g_filename_to_utf8(url, -1, NULL, NULL, NULL);
+    AUDDBG("f: audmad_get_song_info: %s\n", tmp);
+    g_free(tmp);
+#endif                          /* DEBUG */
+
+    if (input_init(&myinfo, url, NULL) == FALSE) {
+        AUDDBG("error initialising input\n");
+        return;
+    }
+
+    if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config->fast_play_time_calc) == TRUE) {
+        if(aud_tuple_get_string(myinfo.tuple, -1, "track-name"))
+            *title = g_strdup(aud_tuple_get_string(myinfo.tuple, -1, "track-name"));
+        else
+            *title = g_strdup(url);
+
+        *length = aud_tuple_get_int(myinfo.tuple, FIELD_LENGTH, NULL);
+        if(*length == -1)
+            *length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
+    }
+    else {
+        *title = g_strdup(url);
+        *length = -1;
+    }
+    input_term(&myinfo);
+    AUDDBG("e: audmad_get_song_info\n");
+}
+
+static gboolean
+audmad_fill_info(struct mad_info_t *info, VFSFile *fd)
+{
+    if (fd == NULL || info == NULL) return FALSE;
+    AUDDBG("f: audmad_fill_info(): %s\n", fd->uri);
+
+    if (input_init(info, fd->uri, fd) == FALSE) {
+        AUDDBG("audmad_fill_info(): error initialising input\n");
+        return FALSE;
+    }
+    
+    info->fileinfo_request = FALSE; /* we don't need to read tuple again */
+    return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config->fast_play_time_calc);
+}
+
+static void
+audmad_about()
+{
+    static GtkWidget *aboutbox;
+    gchar *scratch;
+
+    if (aboutbox != NULL)
+        return;
+
+    scratch = g_strdup_printf(
+    _("Audacious MPEG Audio Plugin\n"
+    "\n"
+    "Compiled against libMAD version: %d.%d.%d%s\n"
+    "\n"
+    "Written by:\n"
+    "    William Pitcock <nenolod@sacredspiral.co.uk>\n"
+    "    Yoshiki Yazawa <yaz@cc.rim.or.jp>\n"
+    "\n"
+    "Portions derived from XMMS-MAD by:\n"
+    "    Sam Clegg\n"
+    "\n"
+    "ReplayGain support by:\n"
+    "    Samuel Krempp"),
+    MAD_VERSION_MAJOR, MAD_VERSION_MINOR, MAD_VERSION_PATCH,
+    MAD_VERSION_EXTRA);
+
+    aboutbox = audacious_info_dialog(_("About MPEG Audio Plugin"),
+                                 scratch,
+                                 _("Ok"), FALSE, NULL, NULL);
+
+    g_free(scratch);
+
+    g_signal_connect(G_OBJECT(aboutbox), "destroy",
+                     G_CALLBACK(gtk_widget_destroyed), &aboutbox);
+}
+
+/**
+ * Display a GTK box containing the given error message.
+ * Taken from mpg123 plugin.
+ */
+void
+audmad_error(char *error, ...)
+{
+#ifndef NOGUI
+    if (!error_dialog) {
+        va_list args;
+        char string[256];
+        va_start(args, error);
+        vsnprintf(string, 256, error, args);
+        va_end(args);
+        GDK_THREADS_ENTER();
+        error_dialog =
+            audacious_info_dialog(_("Error"), string, _("Ok"), FALSE, 0, 0);
+        gtk_signal_connect(GTK_OBJECT(error_dialog), "destroy",
+                           GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                           &error_dialog);
+        GDK_THREADS_LEAVE();
+    }
+#endif                          /* !NOGUI */
+}
+
+extern void audmad_configure();
+
+static void
+__set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value)
+{
+    aud_tuple_associate_string(tuple, nfield, name, value);
+    g_free(value);
+}
+
+// tuple stuff
+static Tuple *
+__audmad_get_song_tuple(char *filename, VFSFile *fd)
+{
+    Tuple *tuple = NULL;
+    gchar *string = NULL;
+
+    struct id3_file *id3file = NULL;
+    struct id3_tag *tag = NULL;
+
+    struct mad_info_t myinfo;
+
+    gboolean local_fd = FALSE;
+    int length;
+
+#ifdef AUD_DEBUG
+    string = aud_str_to_utf8(filename);
+    AUDDBG("f: mad: audmad_get_song_tuple: %s\n", string);
+    g_free(string);
+    string = NULL;
+#endif
+
+    /* isn't is obfuscated? --eugene */
+
+    if(info.remote && mad_timer_count(info.duration, MAD_UNITS_SECONDS) <= 0){
+        if((fd && aud_vfs_is_streaming(fd)) || (info.playback && info.playback->playing)) {
+            gchar *tmp = NULL;
+            tuple = aud_tuple_new_from_filename(filename);
+
+#ifdef AUD_DEBUG
+            if(info.playback)
+                AUDDBG("info.playback->playing = %d\n",info.playback->playing);
+#endif
+            tmp = aud_vfs_get_metadata(info.infile ? info.infile : fd, "track-name");
+            if(tmp){
+                gchar *scratch;
+
+                scratch = aud_str_to_utf8(tmp);
+                aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, scratch);
+                g_free(tmp);
+                g_free(scratch);
+
+                tmp = NULL;
+            }
+            tmp = aud_vfs_get_metadata(info.infile ? info.infile : fd, "stream-name");
+            if(tmp){
+                gchar *scratch;
+
+                scratch = aud_str_to_utf8(tmp);
+                aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, scratch);
+                g_free(tmp);
+                g_free(scratch);
+
+                tmp = NULL;
+            }
+
+            AUDDBG("audmad_get_song_tuple: track_name = %s\n", aud_tuple_get_string(tuple, -1, "track-name"));
+            AUDDBG("audmad_get_song_tuple: stream_name = %s\n", aud_tuple_get_string(tuple, -1, "stream-name"));
+            aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1);
+            aud_tuple_associate_int(tuple, FIELD_MTIME, NULL, 0); // this indicates streaming
+            AUDDBG("get_song_tuple: remote: tuple\n");
+            return tuple;
+        }
+        AUDDBG("get_song_tuple: remote: NULL\n");
+    } /* info.remote  */
+
+    // if !fd, pre-open the file with aud_vfs_fopen() and reuse fd.
+    if(!fd) {
+        fd = aud_vfs_fopen(filename, "rb");
+        if(!fd)
+            return NULL;
+        local_fd = TRUE;
+    }
+
+    if (!audmad_fill_info(&myinfo, fd)) {
+        AUDDBG("get_song_tuple: error obtaining info\n");
+        if (local_fd) aud_vfs_fclose(fd);
+        return NULL;
+    }
+
+    tuple = aud_tuple_new();
+    aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1);
+
+    id3file = id3_file_vfsopen(fd, ID3_FILE_MODE_READONLY);
+
+    if (id3file) {
+
+        tag = id3_file_tag(id3file);
+        if (tag) {
+            __set_and_free(tuple, FIELD_ARTIST, NULL, input_id3_get_string(tag, ID3_FRAME_ARTIST));
+            __set_and_free(tuple, FIELD_ALBUM, NULL, input_id3_get_string(tag, ID3_FRAME_ALBUM));
+            __set_and_free(tuple, FIELD_TITLE, NULL, input_id3_get_string(tag, ID3_FRAME_TITLE));
+
+            // year
+            string = NULL;
+            string = input_id3_get_string(tag, ID3_FRAME_YEAR); //TDRC
+            if (!string)
+                string = input_id3_get_string(tag, "TYER");
+
+            if (string) {
+                aud_tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(string));
+                g_free(string);
+                string = NULL;
+            }
+
+            __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename));
+            __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename));
+            aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename));
+
+            // length
+            length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
+            aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, length);
+
+            // track number
+            string = input_id3_get_string(tag, ID3_FRAME_TRACK);
+            if (string) {
+                aud_tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, atoi(string));
+                g_free(string);
+                string = NULL;
+            }
+            // genre
+            __set_and_free(tuple, FIELD_GENRE, NULL, input_id3_get_string(tag, ID3_FRAME_GENRE));
+            __set_and_free(tuple, FIELD_COMMENT, NULL, input_id3_get_string(tag, ID3_FRAME_COMMENT));
+            AUDDBG("genre = %s\n", aud_tuple_get_string(tuple, FIELD_GENRE, NULL));
+        }
+        id3_file_close(id3file);
+    } // id3file
+    else { // no id3tag
+        __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename));
+        __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename));
+        aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename));
+        // length
+        length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS);
+        aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, length);
+    }
+
+    aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, "lossy");
+    aud_tuple_associate_int(tuple, FIELD_BITRATE, NULL, myinfo.bitrate / 1000);
+
+    string = g_strdup_printf("MPEG-1 Audio Layer %d", myinfo.mpeg_layer);
+    aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, string);
+    g_free(string);
+
+    aud_tuple_associate_string(tuple, FIELD_MIMETYPE, NULL, "audio/mpeg");
+    
+    input_term(&myinfo);
+
+    if(local_fd)
+        aud_vfs_fclose(fd);
+
+    AUDDBG("e: mad: audmad_get_song_tuple\n");
+    return tuple;
+}
+
+static Tuple *
+audmad_get_song_tuple(char *filename)
+{
+    return __audmad_get_song_tuple(filename, NULL);
+}
+
+static Tuple *
+audmad_probe_for_tuple(char *filename, VFSFile *fd)
+{
+    if (!audmad_is_our_fd(filename, fd))
+        return NULL;
+
+    aud_vfs_rewind(fd);
+
+    return __audmad_get_song_tuple(filename, fd);
+}
+
+static gchar *fmts[] = { "mp3", "mp2", "mpg", "bmu", NULL };
+
+InputPlugin mad_ip = {
+    .description = "MPEG Audio Plugin",
+    .init = audmad_init,
+    .about = audmad_about,
+    .configure = audmad_configure,
+    .is_our_file = audmad_is_our_file,
+    .play_file = audmad_play_file,
+    .stop = audmad_stop,
+    .pause = audmad_pause,
+    .seek = audmad_seek,
+    .cleanup = audmad_cleanup,
+    .get_song_info = audmad_get_song_info,
+    .get_song_tuple = audmad_get_song_tuple,
+    .is_our_file_from_vfs = audmad_is_our_fd,
+    .vfs_extensions = fmts,
+    .mseek = audmad_mseek,
+    .probe_for_tuple = audmad_probe_for_tuple,
+    .update_song_tuple = audmad_update_song_tuple,
+};
+
+InputPlugin *madplug_iplist[] = { &mad_ip, NULL };
+
+SIMPLE_INPUT_PLUGIN(madplug, madplug_iplist);
+
+InputPlugin *mad_plugin = &mad_ip;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/plugin.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,149 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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 AUD_MAD_H
+#define AUD_MAD_H
+
+/* #define AUD_DEBUG 1 */
+/* #define DEBUG_INTENSIVELY 1 */
+/* #define DEBUG_DITHER 1 */
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "MADPlug"
+
+#undef PACKAGE
+#define PACKAGE "audacious-plugins"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <audacious/plugin.h>
+#include <audacious/main.h>
+#include <audacious/util.h>
+#include <audacious/strings.h>
+#include <audacious/i18n.h>
+#include <audacious/id3tag.h>
+#include <mad.h>
+
+#include "xing.h"
+
+struct mad_info_t
+{
+    /* InputPlayback */
+    InputPlayback *playback;
+
+    /* seek time */
+    gulong seek;      /**< seek time in milliseconds */
+
+    /* state */
+    guint current_frame;/**< current mp3 frame */
+    mad_timer_t pos;    /**< current play position */
+
+    /* song info */
+    guint vbr;      /**< bool: is vbr? */
+    guint bitrate;  /**< avg. bitrate */
+    guint freq;     /**< sample freq. */
+    guint mpeg_layer;   /**< mpeg layer */
+    guint mode;     /**< mpeg stereo mode */
+    guint channels;
+    gint frames;    /**< total mp3 frames or -1 */
+    gint fmt;       /**< sample format */
+    gint size;      /**< file size in bytes or -1 */
+    gchar *title;   /**< title for xmms */
+    mad_timer_t duration;   /**< total play time */
+    struct id3_tag *tag;
+    struct id3_file *id3file;
+    struct xing xing;
+    Tuple *tuple;          /* audacious tuple data */
+    gchar *prev_title;           /* used to optimize set_info calls */
+
+    /* replay parameters */
+    gboolean has_replaygain;
+    double replaygain_album_scale;  // -1 if not set
+    double replaygain_track_scale;
+    gchar *replaygain_album_str;
+    gchar *replaygain_track_str;
+    double replaygain_album_peak;   // -1 if not set
+    double replaygain_track_peak;
+    gchar *replaygain_album_peak_str;
+    gchar *replaygain_track_peak_str;
+    double mp3gain_undo;        // -1 if not set
+    double mp3gain_minmax;
+    gchar *mp3gain_undo_str;
+    gchar *mp3gain_minmax_str;
+
+    /* data access */
+    gchar *url;
+    gchar *filename;
+    VFSFile *infile;
+    gint offset;
+
+    /* flags */
+    gboolean remote;
+    gboolean fileinfo_request;
+
+};
+
+typedef struct audmad_config_t
+{
+    gboolean fast_play_time_calc;
+    gboolean use_xing;
+    gboolean dither;
+    gboolean sjis;
+
+    struct
+    {
+        gchar *preamp0_db;          // gain applied to samples at decoding stage.
+        gdouble preamp0_scale;      // pow(10, pregain/20)
+        gboolean enable;
+        gboolean track_mode;
+        gchar *preamp1_db;      // preamp used with RG info.
+        gdouble preamp1_scale;
+        gchar *preamp2_db;      // preamp used without RG info.
+        gdouble preamp2_scale;
+        gboolean anti_clip;
+        gboolean adaptive_scaler;
+    } replaygain;
+
+    gboolean title_override;
+    gchar *id3_format;
+    gboolean show_avg_vbr_bitrate;
+    gboolean force_reopen_audio;
+} audmad_config_t;
+
+// global variables
+extern InputPlugin *mad_plugin;
+extern audmad_config_t *audmad_config;
+
+// gcond
+extern GMutex *mad_mutex;
+extern GMutex *pb_mutex;
+extern GCond *mad_cond;
+
+// prototypes
+void audmad_config_compute(struct audmad_config_t *config);
+void input_process_remote_metadata(struct mad_info_t *info);
+gpointer decode_loop(gpointer arg);
+void audmad_error(gchar * fmt, ...);
+void audmad_configure(void);
+
+#endif                          /* !AUD_MAD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/replaygain.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,349 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ * Copyright (C) 2001-2007 Samuel Krempp
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+#include "plugin.h"
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <assert.h>
+#include "replaygain.h"
+
+static unsigned long
+Read_LE_Uint32(const unsigned char *p)
+{
+    return ((unsigned long) p[0] << 0) |
+        ((unsigned long) p[1] << 8) |
+        ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24);
+}
+
+static int
+uncase_strcmp(const char *s1, const char *s2)
+{
+    int l1 = strlen(s1);
+    int l2 = strlen(s2);
+    int i;
+    for (i = 0; i < l1 && i < l2; ++i) {
+        if (toupper(s1[i]) < toupper(s2[i]))
+            return -1;
+    }
+    if (l1 == l2)
+        return 0;
+    return (l1 < l2) ? -1 : +1;
+}
+
+static gdouble
+strgain2double(gchar * s, int len)
+{
+    gdouble res = g_strtod(s, NULL);    // gain, in dB.
+    if (res == 0)
+        return 1;
+    return pow(10, res / 20);
+}
+
+// Reads APE v2.0 tag ending at current pos in fp
+
+static int
+ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file_info)
+{
+    unsigned long vsize;
+    unsigned long isize;
+    unsigned long flags;
+    char *buff;
+    char *p;
+    char *end;
+    struct APETagFooterStruct T, *tp;
+    unsigned long TagLen;
+    unsigned long TagCount;
+
+    tp = &T;
+
+    if (aud_vfs_fseek(fp, -sizeof(T), SEEK_CUR) != 0)
+        return 18;
+    if (aud_vfs_fread(tp, 1, sizeof(T), fp) != sizeof T)
+        return 2;
+    if (memcmp(tp->ID, "APETAGEX", sizeof(tp->ID)) != 0)
+        return 3;
+    if (Read_LE_Uint32(tp->Version) != 2000)
+        return 4;
+    TagLen = Read_LE_Uint32(tp->Length);
+    if (TagLen < sizeof(T))
+        return 5;
+    if (aud_vfs_fseek(fp, -TagLen, SEEK_CUR) != 0)
+        return 6;
+    if ((buff = (char *) malloc(TagLen)) == NULL) {
+        return 7;
+    }
+    if (aud_vfs_fread(buff, 1, TagLen - sizeof(T), fp) != TagLen - sizeof(T)) {
+        free(buff);
+        return 8;
+    }
+
+    AUDDBG("ver = %ld\n", Read_LE_Uint32(tp->Version));
+    AUDDBG("taglen = %ld\n", TagLen);
+
+    TagCount = Read_LE_Uint32(tp->TagCount);
+    end = buff + TagLen - sizeof(T);
+    for (p = buff; p < end && TagCount--;) {
+        vsize = Read_LE_Uint32((unsigned char *)p);
+        p += 4;
+        flags = Read_LE_Uint32((unsigned char *)p);
+        p += 4;
+        isize = strlen((char *) p);
+
+        if (isize > 0 && vsize > 0) {
+            gdouble *scale = NULL;
+            gchar **str = NULL;
+            if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_GAIN") == 0) {
+                scale = &file_info->replaygain_album_scale;
+                str = &file_info->replaygain_album_str;
+            }
+            if (uncase_strcmp(p, "REPLAYGAIN_TRACK_GAIN") == 0) {
+                scale = &file_info->replaygain_track_scale;
+                str = &file_info->replaygain_track_str;
+            }
+            if (str != NULL) {
+                assert(scale != NULL);
+                *scale = strgain2double(p + isize + 1, vsize);
+                *str = g_strndup(p + isize + 1, vsize);
+            }
+            //* case of peak info tags : */
+            str = NULL;
+            if (uncase_strcmp(p, "REPLAYGAIN_TRACK_PEAK") == 0) {
+                scale = &file_info->replaygain_track_peak;
+                str = &file_info->replaygain_track_peak_str;
+            }
+            if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_PEAK") == 0) {
+                scale = &file_info->replaygain_album_peak;
+                str = &file_info->replaygain_album_peak_str;
+            }
+            if (str != NULL) {
+                *scale = g_strtod(p + isize + 1, NULL);
+                *str = g_strndup(p + isize + 1, vsize);
+            }
+
+            /* mp3gain additional tags : 
+               the gain tag translates to scale = 2^(gain/4), 
+               i.e., in dB : 20*log(2)/log(10)*gain/4
+               -> 1.501*gain dB
+             */
+            if (uncase_strcmp(p, "MP3GAIN_UNDO") == 0) {
+                str = &file_info->mp3gain_undo_str;
+                scale = &file_info->mp3gain_undo;
+                assert(4 < vsize);  /* this tag is +left,+right */
+                *str = g_strndup(p + isize + 1, vsize);
+                *scale = 1.50515 * atoi(*str);
+            }
+            if (uncase_strcmp(p, "MP3GAIN_MINMAX") == 0) {
+                str = &file_info->mp3gain_minmax_str;
+                scale = &file_info->mp3gain_minmax;
+                *str = g_strndup(p + isize + 1, vsize);
+                assert(4 < vsize);  /* this tag is min,max */
+                *scale = 1.50515 * (atoi((*str) + 4) - atoi(*str));
+            }
+        }
+        p += isize + 1 + vsize;
+    }
+
+    free(buff);
+
+    return 0;
+}
+
+static int
+find_offset(VFSFile * fp)
+{
+    static const char *key = "APETAGEX";
+    char buff[20000];
+    int N = 0;
+    if (aud_vfs_fseek(fp, -20000, SEEK_CUR) != 0);
+    if ((N = aud_vfs_fread(buff, 1, 20000, fp)) < 16)
+        return 1;
+    int matched = 0;
+    int i, last_match = -1;
+    for (i = 0; i < N; ++i) {
+        if (buff[i] == key[matched])
+            ++matched;
+        else {
+            if (matched == 5 && buff[i] == 'P')
+                matched = 2;    // got "APET" + "AP"
+            else
+                matched = 0;
+        }
+        if (matched == 8) {
+            last_match = i;
+            matched = 0;
+        }
+    }
+    if (last_match == -1)
+        return 1;
+    return last_match + 1 - 8 + sizeof(struct APETagFooterStruct) - N;
+}
+
+/* Eugene Zagidullin:
+ * Read ReplayGain info from foobar2000-style id3v2 frames */
+
+static int
+ReadId3v2TXXX(struct mad_info_t *file_info)
+{
+	int i;
+	char *key;
+	char *value;
+	struct id3_frame *frame;
+
+	AUDDBG("f: ReadId3v2TXXX\n");
+
+	/* tag must be read before! */
+	if (! file_info->tag ) {
+		AUDDBG("id3v2 not found\n");
+		return 0;
+	}
+
+	/* Partially based on code from MPD (http://www.musicpd.org/) */
+	for (i = 0; (frame = id3_tag_findframe(file_info->tag, "TXXX", i)); i++) {
+		if (frame->nfields < 3)
+			continue;
+
+		key = (char *)
+		    id3_ucs4_latin1duplicate(id3_field_getstring
+					     (&frame->fields[1]));
+		value = (char *)
+		    id3_ucs4_latin1duplicate(id3_field_getstring
+					     (&frame->fields[2]));
+
+		if (strcasecmp(key, "replaygain_track_gain") == 0) {
+			file_info->replaygain_track_scale = strgain2double(value, strlen(value));
+			file_info->replaygain_track_str = g_strdup(value);
+		} else if (strcasecmp(key, "replaygain_album_gain") == 0) {
+			file_info->replaygain_album_scale = strgain2double(value, strlen(value));
+			file_info->replaygain_album_str = g_strdup(value);
+		} else if (strcasecmp(key, "replaygain_track_peak") == 0) {
+			file_info->replaygain_track_peak = g_strtod(value, NULL);
+			file_info->replaygain_track_peak_str = g_strdup(value);
+		} else if (strcasecmp(key, "replaygain_album_peak") == 0) {
+			file_info->replaygain_album_peak = g_strtod(value, NULL);
+			file_info->replaygain_album_peak_str = g_strdup(value);
+		}
+
+		free(key);
+		free(value);
+	}
+
+	if (file_info->replaygain_track_scale != -1 || file_info->replaygain_album_scale != -1)
+	{
+		file_info->has_replaygain = TRUE;
+		return 1;
+	}
+
+	return 0;
+}
+
+void
+read_replaygain(struct mad_info_t *file_info)
+{
+    VFSFile *fp;
+    glong curpos = 0;
+
+    AUDDBG("f: read_replaygain\n");
+
+    file_info->has_replaygain = FALSE;
+    file_info->replaygain_album_scale = -1;
+    file_info->replaygain_track_scale = -1;
+    file_info->mp3gain_undo = -77;
+    file_info->mp3gain_minmax = -77;
+
+    if (ReadId3v2TXXX(file_info)) {
+        AUDDBG("found ReplayGain info in id3v2 tag\n");
+#ifdef AUD_DEBUG
+	gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL);
+
+        AUDDBG("RG album scale= %g, RG track scale = %g, in %s\n",
+		  file_info->replaygain_album_scale,
+		  file_info->replaygain_track_scale, tmp);
+        g_free(tmp);
+#endif
+	return;
+    }
+
+
+    /* APEv2 stuff */
+    if (file_info->infile) {
+        fp = aud_vfs_dup(file_info->infile);
+        curpos = aud_vfs_ftell(fp);
+    }
+    else {
+        if ((fp = aud_vfs_fopen(file_info->filename, "rb")) == NULL)
+            return;
+    }
+
+    if (aud_vfs_fseek(fp, 0L, SEEK_END) != 0) {
+        aud_vfs_fclose(fp);
+        return;
+    }
+    
+    long pos = aud_vfs_ftell(fp);
+    int res = -1;
+    int try = 0;
+    while (res != 0 && try < 10) {
+        // try skipping an id3 tag
+        aud_vfs_fseek(fp, pos, SEEK_SET);
+        aud_vfs_fseek(fp, try * -128, SEEK_CUR);
+        res = ReadAPE2Tag(fp, file_info);
+        ++try;
+    }
+    if (res != 0) {
+        // try brute search (don't want to parse all possible kinds of tags..)
+        aud_vfs_fseek(fp, pos, SEEK_SET);
+        int offs = find_offset(fp);
+        if (offs <= 0) {        // found !
+            aud_vfs_fseek(fp, pos, SEEK_SET);
+            aud_vfs_fseek(fp, offs, SEEK_CUR);
+            res = ReadAPE2Tag(fp, file_info);
+            if (res != 0) {
+                g_message
+                    ("hmpf, was supposed to find a tag.. offs=%d, res=%d",
+                     offs, res);
+            }
+        }
+        else 
+            AUDDBG("replaygain: not found\n");
+    }
+#ifdef AUD_DEBUG
+    if (res == 0) {             // got APE tags, show the result
+        gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL);        
+        AUDDBG("RG album scale= %g, RG track scale = %g, in %s\n",
+		  file_info->replaygain_album_scale,
+		  file_info->replaygain_track_scale, tmp);
+        g_free(tmp);
+    }
+#endif
+
+    if (file_info->replaygain_album_scale != -1
+        || file_info->replaygain_track_scale != -1)
+        file_info->has_replaygain = TRUE;
+
+    if (file_info->infile)
+        aud_vfs_fseek(fp, curpos, SEEK_SET);
+
+    aud_vfs_fclose(fp);
+
+    AUDDBG("e: read_replaygain\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/replaygain.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,44 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ * Copyright (C) 2001-2007 Samuel Krempp
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+#include "plugin.h"
+#include "stdlib.h"
+#include "math.h"
+#include "ctype.h"
+
+#ifndef __replaygain_h__
+#define __replaygain_h__
+
+struct APETagFooterStruct
+{
+    unsigned char ID[8];
+    unsigned char Version[4];
+    unsigned char Length[4];
+    unsigned char TagCount[4];
+    unsigned char Flags[4];
+    unsigned char Reserved[8];
+};
+
+/* prototypes */
+void read_replaygain(struct mad_info_t *file_info);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/tuple.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,188 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include "plugin.h"
+#include "tuple.h"
+#include "input.h"
+
+#include <math.h>
+#include <string.h>
+
+#include <glib.h> 
+#include <glib/gprintf.h>
+
+#include <audacious/util.h>
+#include <audacious/plugin.h>
+#include <audacious/id3tag.h>
+
+#include <langinfo.h>
+
+static void
+update_id3_frame(struct id3_tag *tag, const char *frame_name, const char *data, int sjis)
+{
+    int res;
+    struct id3_frame *frame;
+    union id3_field *field;
+    id3_ucs4_t *ucs4;
+
+    if (data == NULL)
+        return;
+
+    /* printf ("updating id3: %s: %s\n", frame_name, data);
+
+    
+     An empty string removes the frame altogether.
+    */
+    if (strlen(data) == 0) {
+        while ((frame = id3_tag_findframe(tag, frame_name, 0))) {
+            AUDDBG("madplug: detachframe\n");
+            id3_tag_detachframe(tag, frame);
+        }
+        return;
+    }
+
+    frame = id3_tag_findframe(tag, frame_name, 0);
+    if (!frame) {
+        AUDDBG("frame_new\n");
+        frame = id3_frame_new(frame_name);
+        id3_tag_attachframe(tag, frame);
+    }
+
+    /* setup ucs4 string */
+    if(sjis) {
+        ucs4 = id3_latin1_ucs4duplicate((id3_latin1_t *) data);
+    }
+    else {
+        ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) data);
+    }
+
+    /* set encoding */
+    field = id3_frame_field(frame, 0);
+    id3_field_settextencoding(field, sjis ? ID3_FIELD_TEXTENCODING_ISO_8859_1 :
+			      ID3_FIELD_TEXTENCODING_UTF_8);
+
+    /* setup genre code */
+    if (!strcmp(frame_name, ID3_FRAME_GENRE)) {
+        char *tmp;
+        int index = id3_genre_number(ucs4);
+        g_free(ucs4);
+
+        if(index == -1) { /* unknown genre. remove TCON frame. */
+            AUDDBG("madplug: remove genre frame\n");
+            id3_tag_detachframe(tag, frame);
+        }
+        else { /* meaningful genre */
+            tmp = g_strdup_printf("%d", index);
+            ucs4 = id3_latin1_ucs4duplicate((unsigned char *) tmp);
+        }
+
+    }
+
+    /* write string */
+    if (!strcmp(frame_name, ID3_FRAME_COMMENT)) {
+        field = id3_frame_field(frame, 3);
+        field->type = ID3_FIELD_TYPE_STRINGFULL;
+        res = id3_field_setfullstring(field, ucs4);
+    }
+    else {
+        field = id3_frame_field(frame, 1);
+        field->type = ID3_FIELD_TYPE_STRINGLIST;
+        res = id3_field_setstrings(field, 1, &ucs4);
+    }
+
+    if (res != 0)
+        g_print("error setting id3 field: %s\n", frame_name);
+}
+
+static void
+update_id3_frame_from_tuple(struct id3_tag *id3tag, const char *field, Tuple *tuple, int fieldn, int sjis)
+{   
+    int val;
+    char *text, *text2;
+    const char *encoding = sjis ? "SJIS" : "UTF-8";
+
+    if(aud_tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) {
+        val = aud_tuple_get_int(tuple, fieldn, NULL);
+        if(val > 0) {
+            text2 = g_strdup_printf("%d", val);
+            AUDDBG("madplug: updating field:\"%s\"=\"%s\", enc %s\n", field, text2, encoding);
+            update_id3_frame(id3tag, field, text2, 0);
+            g_free(text2);
+        } else {
+            update_id3_frame(id3tag, field, "", 0); /* will be detached */
+        }
+
+    } else if(aud_tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_STRING) {
+        text = (char*)aud_tuple_get_string(tuple, fieldn, NULL);
+        text2 = g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL);
+        AUDDBG("madplug: updating field:\"%s\"=\"%s\", enc %s\n", field, text2, encoding);
+        update_id3_frame(id3tag, field, text2, sjis);
+        g_free(text2);
+    }
+}
+
+gboolean
+audmad_update_song_tuple(Tuple *tuple, VFSFile *fd)
+{
+    struct id3_file *id3file;
+    struct id3_tag *id3tag;
+    gchar *text;
+    struct mad_info_t songinfo;
+
+    if ((id3file = id3_file_vfsopen(fd, ID3_FILE_MODE_READWRITE)) == NULL) return FALSE;
+    
+    id3tag = id3_file_tag(id3file);
+    if (!id3tag) {
+        AUDDBG("no id3tag\n. append new tag.\n");
+        id3tag = id3_tag_new();
+        id3_tag_clearframes(id3tag);
+        id3tag->options |= ID3_TAG_OPTION_APPENDEDTAG | ID3_TAG_OPTION_ID3V1;
+    }
+
+    id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0);    /* enables id3v1. TODO: make id3v1 optional */
+    
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TITLE, tuple, FIELD_TITLE, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ARTIST, tuple, FIELD_ARTIST, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_ALBUM, tuple, FIELD_ALBUM, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_YEAR, tuple, FIELD_YEAR, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_COMMENT, tuple, FIELD_COMMENT, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_TRACK, tuple, FIELD_TRACK_NUMBER, audmad_config->sjis);
+    update_id3_frame_from_tuple(id3tag, ID3_FRAME_GENRE, tuple, FIELD_GENRE, audmad_config->sjis);
+
+    if(!id3_tag_findframe(id3tag, "TLEN", 0) && input_init(&songinfo, fd->uri, fd) && !songinfo.remote) {
+        AUDDBG("update TLEN frame\n");
+        songinfo.fileinfo_request = FALSE; /* we don't need to read tuple again */
+        input_get_info(&songinfo, FALSE);
+        text = g_strdup_printf("%ld", mad_timer_count(songinfo.duration, MAD_UNITS_MILLISECONDS));
+        AUDDBG("TLEN: \"%s\"\n", text);
+        update_id3_frame(id3tag, "TLEN", text, 0);
+        g_free(text);
+        input_term(&songinfo);
+    }
+
+    if (id3_file_update(id3file) != 0) return FALSE;
+
+    id3_file_close(id3file);
+    return TRUE;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/tuple.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,30 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin
+ *
+ * Portions derived from xmms-mad:
+ * Copyright (C) 2001-2002 Sam Clegg - See COPYING
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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 TUPLE_H
+#define TUPLE_H
+
+#include <glib.h>
+#include <audacious/plugin.h>
+
+gboolean audmad_update_song_tuple(Tuple *tuple, VFSFile *fd);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/xing.c	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,97 @@
+/*
+ * mad plugin for audacious
+ * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa
+ *
+ * Derived from: 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; under version 2 of the License.
+ *
+ * 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
+ */
+
+#include <mad.h>
+
+#include "xing.h"
+
+#define XING_MAGIC	(('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
+
+/*
+ * NAME:	xing->init()
+ * DESCRIPTION:	initialize Xing structure
+ */
+void
+xing_init(struct xing *xing)
+{
+    xing->flags = 0;
+    xing->frames = 0;
+    xing->bytes = 0;
+    xing->toc[0] = '\0';
+    xing->scale = 0;
+}
+
+/*
+ * NAME:	xing->parse()
+ * DESCRIPTION:	parse a Xing VBR header
+ */
+int
+xing_parse(struct xing *xing, struct mad_bitptr ptr,
+               unsigned int bitlen)
+{
+    if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
+        goto fail;
+
+    xing->flags = mad_bit_read(&ptr, 32);
+    bitlen -= 64;
+
+    if (xing->flags & XING_FRAMES) {
+        if (bitlen < 32)
+            goto fail;
+
+        xing->frames = mad_bit_read(&ptr, 32);
+        bitlen -= 32;
+    }
+
+    if (xing->flags & XING_BYTES) {
+        if (bitlen < 32)
+            goto fail;
+
+        xing->bytes = mad_bit_read(&ptr, 32);
+        bitlen -= 32;
+    }
+
+    if (xing->flags & XING_TOC) {
+        int i;
+
+        if (bitlen < 800)
+            goto fail;
+
+        for (i = 0; i < 100; ++i)
+            xing->toc[i] = mad_bit_read(&ptr, 8);
+
+        bitlen -= 800;
+    }
+
+    if (xing->flags & XING_SCALE) {
+        if (bitlen < 32)
+            goto fail;
+
+        xing->scale = mad_bit_read(&ptr, 32);
+        bitlen -= 32;
+    }
+
+    return 0;
+
+  fail:
+    xing->flags = 0;
+    return -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/madplug_x/xing.h	Tue Feb 05 01:11:50 2008 +0900
@@ -0,0 +1,48 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef XING_H
+#define XING_H
+
+#include "mad.h"
+
+struct xing
+{
+    long flags;                 /* valid fields (see below) */
+    unsigned long frames;       /* total number of frames */
+    unsigned long bytes;        /* total number of bytes */
+    unsigned char toc[100];     /* 100-point seek table */
+    long scale;                 /* ?? */
+};
+
+enum
+{
+    XING_FRAMES = 0x00000001L,
+    XING_BYTES = 0x00000002L,
+    XING_TOC = 0x00000004L,
+    XING_SCALE = 0x00000008L
+};
+
+void xing_init(struct xing *);
+
+#define xing_finish(xing)       /* nothing */
+
+int xing_parse(struct xing *, struct mad_bitptr, unsigned int);
+
+#endif