changeset 430:67cd014f35a2 trunk

[svn] This commit rips out the old equalization engine with a dynamic engine that can be extended all the way up to 128 bands.
author nenolod
date Sat, 14 Jan 2006 16:49:00 -0800
parents e9569b4111b4
children 4d1aa30a8776
files audacious/Makefile.am audacious/iir.c audacious/iir.h audacious/iir_cfs.c audacious/iir_cfs.h audacious/iir_fpu.c audacious/iir_fpu.h audacious/output.c
diffstat 8 files changed, 637 insertions(+), 156 deletions(-) [+]
line wrap: on
line diff
--- a/audacious/Makefile.am	Sat Jan 14 11:03:49 2006 -0800
+++ b/audacious/Makefile.am	Sat Jan 14 16:49:00 2006 -0800
@@ -73,6 +73,8 @@
 	mkdtemp.c \
 	pixmaps.h \
 	iir.c iir.h \
+	iir_cfs.c iir_cfs.h \
+	iir_fpu.c iir_fpu.h \
 	na.xpm beep_logo.xpm
 
 beepinclude_HEADERS = plugin.h output.h input.h
--- a/audacious/iir.c	Sat Jan 14 11:03:49 2006 -0800
+++ b/audacious/iir.c	Sat Jan 14 16:49:00 2006 -0800
@@ -1,7 +1,7 @@
 /*
  *   PCM time-domain equalizer
  *
- *   Copyright (C) 2002  Felipe Rivera <liebremx at users sourceforge net>
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users sourceforge net>
  *
  *   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
@@ -17,166 +17,69 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *   $Id: iir.c,v 1.5 2004/06/20 18:48:54 mderezynski Exp $
+ *   $Id: iir.c,v 1.15 2005/10/17 01:57:59 liebremx Exp $
  */
 
-#include "equalizer.h"
-#include "main.h"
 #include <math.h>
-#include <string.h>
-#include "output.h"
-
 #include "iir.h"
 
-// Fixed Point Fractional bits
-#define FP_FRBITS 28
-
-// Conversions
-#define EQ_REAL(x) ((gint)((x) * (1 << FP_FRBITS)))
+/* Coefficients */
+sIIRCoefficients *iir_cf;
 
-/* Floating point */
-typedef struct {
-    float beta;
-    float alpha;
-    float gamma;
-} sIIRCoefficients;
-
-/* Coefficient history for the IIR filter */
-typedef struct {
-    float x[3];                 /* x[n], x[n-1], x[n-2] */
-    float y[3];                 /* y[n], y[n-1], y[n-2] */
-} sXYData;
+/* Volume gain 
+ * values should be between 0.0 and 1.0 
+ * Use the preamp from XMMS for now
+ * */
+float preamp[EQ_CHANNELS];
 
-/* BETA, ALPHA, GAMMA */
-static sIIRCoefficients iir_cforiginal10[] = {
-    {(9.9421504945e-01), (2.8924752745e-03), (1.9941421835e+00)},   /*    60.0 Hz */
-    {(9.8335039428e-01), (8.3248028618e-03), (1.9827686547e+00)},   /*   170.0 Hz */
-    {(9.6958094144e-01), (1.5209529281e-02), (1.9676601546e+00)},   /*   310.0 Hz */
-    {(9.4163923306e-01), (2.9180383468e-02), (1.9345490229e+00)},   /*   600.0 Hz */
-    {(9.0450844499e-01), (4.7745777504e-02), (1.8852109613e+00)},   /*  1000.0 Hz */
-    {(7.3940088234e-01), (1.3029955883e-01), (1.5829158753e+00)},   /*  3000.0 Hz */
-    {(5.4697667908e-01), (2.2651166046e-01), (1.0153238114e+00)},   /*  6000.0 Hz */
-    {(3.1023210589e-01), (3.4488394706e-01), (-1.8142472036e-01)},  /* 12000.0 Hz */
-    {(2.6718639778e-01), (3.6640680111e-01), (-5.2117742267e-01)},  /* 14000.0 Hz */
-    {(2.4201241845e-01), (3.7899379077e-01), (-8.0847117831e-01)},  /* 16000.0 Hz */
-};
-
-/* History for two filters */
-static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS];
-static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS];
+#ifdef BENCHMARK
+#include "benchmark.h"
+double timex = 0.0;
+int count = 0;
+unsigned int blength = 0;
+#endif
 
-/* Coefficients */
-static sIIRCoefficients *iir_cf;
-
-/* Gain for each band
- * values should be between -0.2 and 1.0 */
-float gain[10];
-float preamp;
-
-int round_trick(float floatvalue_to_round);
+/* 
+ * Global vars
+ */
+gint rate;
+int band_count;
 
-/* Init the filter */
-void
-init_iir()
+void set_preamp(gint chn, float val)
 {
-    iir_cf = iir_cforiginal10;
-
-    /* Zero the history arrays */
-    memset(data_history, 0, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
-    memset(data_history2, 0, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
-
-    output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp,
-                  cfg.equalizer_bands);
+  preamp[chn] = val;
 }
 
-int
-iir(gpointer * d, gint length)
+/* Init the filters */
+void init_iir()
 {
-    gint16 *data = (gint16 *) * d;
-    static gint i = 0, j = 2, k = 1;
-
-    gint index, band, channel;
-    gint tempgint, halflength;
-    float out[EQ_CHANNELS], pcm[EQ_CHANNELS];
-
-    halflength = (length >> 1);
-    for (index = 0; index < halflength; index += 2) {
-        /* For each channel */
-        for (channel = 0; channel < EQ_CHANNELS; channel++) {
-            /* No need to scale when processing the PCM with the filter */
-            pcm[channel] = data[index + channel];
+  calc_coeffs();
+#if 0
+  band_count = cfg.band_num;
+#endif
 
-            /* Preamp gain */
-            pcm[channel] *= preamp;
+  band_count = 10;
+
+  rate = 44100;
 
-            out[channel] = 0;
-            /* For each band */
-            for (band = 0; band < 10; band++) {
-                /* Store Xi(n) */
-                data_history[band][channel].x[i] = pcm[channel];
-                /* Calculate and store Yi(n) */
-                data_history[band][channel].y[i] =
-                    (iir_cf[band].alpha * (data_history[band][channel].x[i]
-                                           - data_history[band][channel].x[k])
-                     + iir_cf[band].gamma * data_history[band][channel].y[j]
-                     - iir_cf[band].beta * data_history[band][channel].y[k]);
-                /*
-                 * The multiplication by 2.0 was 'moved' into the coefficients to save
-                 * CPU cycles here */
-                /* Apply the gain  */
-                out[channel] += data_history[band][channel].y[i] * gain[band];
-            }                   /* For each band */
+  iir_cf = get_coeffs(&band_count, rate, TRUE);
+  clean_history();
+}
 
-            if (cfg.eq_extra_filtering) {
-                /* Filter the sample again */
-                for (band = 0; band < 10; band++) {
-                    /* Store Xi(n) */
-                    data_history2[band][channel].x[i] = out[channel];
-                    /* Calculate and store Yi(n) */
-                    data_history2[band][channel].y[i] =
-                        (iir_cf[band].alpha *
-                         (data_history2[band][channel].x[i]
-                          - data_history2[band][channel].x[k])
-                         +
-                         iir_cf[band].gamma *
-                         data_history2[band][channel].y[j]
-                         -
-                         iir_cf[band].beta * data_history2[band][channel].y[k]
-                        );
-                    /* Apply the gain */
-                    out[channel] +=
-                        data_history2[band][channel].y[i] * gain[band];
-                }               /* For each band */
-            }
-
-            /* Volume stuff
-               Scale down original PCM sample and add it to the filters
-               output. This substitutes the multiplication by 0.25
-             */
+#ifdef ARCH_X86
+/* Round function provided by Frank Klemm which saves around 100K
+ * CPU cycles in my PIII for each call to the IIR function with 4K samples
+ */
+__inline__ int round_trick(float floatvalue_to_round)
+{
+  float   floattmp ;
+  int     rounded_value ;
 
-            out[channel] += (data[index + channel]);
-            tempgint = (int) out[channel];
-
-            if (tempgint < -32768)
-                data[index + channel] = -32768;
-            else if (tempgint > 32767)
-                data[index + channel] = 32767;
-            else
-                data[index + channel] = tempgint;
-        }
+  floattmp      = (int) 0x00FD8000L + (floatvalue_to_round);
+  rounded_value = *(int*)(&floattmp) - (int)0x4B7D8000L;
 
-        i++;
-        j++;
-        k++;
-
-        /* Wrap around the indexes */
-        if (i == 3)
-            i = 0;
-        else if (j == 3)
-            j = 0;
-        else
-            k = 0;
-    }
-
-    return length;
+  if ( rounded_value != (short) rounded_value )
+    rounded_value = ( rounded_value >> 31 ) ^ 0x7FFF;
+  return rounded_value;
 }
+#endif
--- a/audacious/iir.h	Sat Jan 14 11:03:49 2006 -0800
+++ b/audacious/iir.h	Sat Jan 14 16:49:00 2006 -0800
@@ -1,7 +1,7 @@
 /*
  *   PCM time-domain equalizer
  *
- *   Copyright (C) 2002  Felipe Rivera <liebremx at users.sourceforge.net>
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users.sourceforge.net>
  *
  *   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
@@ -17,19 +17,68 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *   $Id: iir.h,v 1.5 2004/06/20 18:48:54 mderezynski Exp $
+ *   $Id: iir.h,v 1.12 2005/10/17 01:57:59 liebremx Exp $
  */
 #ifndef IIR_H
 #define IIR_H
 
-#define EQ_MAX_BANDS 10
-#define EQ_CHANNELS 2
+#include <glib.h>
+#include "main.h"
+#include "iir_cfs.h"
 
-extern float gain[10];
-extern float preamp;
+/*
+ * Flush-to-zero to avoid flooding the CPU with underflow exceptions 
+ */
+#ifdef SSE_MATH
+#define FTZ 0x8000
+#define FTZ_ON { \
+    unsigned int mxcsr; \
+  __asm__  __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \
+  mxcsr |= FTZ; \
+  __asm__  __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \
+}
+#define FTZ_OFF { \
+    unsigned int mxcsr; \
+  __asm__  __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \
+  mxcsr &= ~FTZ; \
+  __asm__  __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \
+}
+#else
+#define FTZ_ON
+#define FTZ_OFF
+#endif
 
-int iir(gpointer * d, gint length);
+/*
+ * Function prototypes
+ */
 void init_iir();
+void clean_history();
+void set_gain(gint index, gint chn, float val);
+void set_preamp(gint chn, float val);
 
 
-#endif                          /* #define IIR_H */
+__inline__ int iir(gpointer * d, gint length, gint nch);
+
+#ifdef ARCH_X86
+__inline__ int round_trick(float floatvalue_to_round);
+#endif
+#ifdef ARCH_PPC
+__inline__ int round_ppc(float x);
+#endif
+
+#define EQ_CHANNELS 2
+#define EQ_MAX_BANDS 10
+
+extern float preamp[EQ_CHANNELS];
+extern sIIRCoefficients *iir_cf;
+extern gint rate;
+extern gint band_count;
+
+#ifdef BENCHMARK
+extern double timex;
+extern int count;
+extern unsigned int blength;
+#endif
+
+#endif /* #define IIR_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/audacious/iir_cfs.c	Sat Jan 14 16:49:00 2006 -0800
@@ -0,0 +1,235 @@
+/*
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users.sourceforge.net>
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *   Coefficient stuff
+ *
+ *   $Id: iir_cfs.c,v 1.1 2005/10/17 01:57:59 liebremx Exp $
+ */
+
+#include "iir_cfs.h"
+#include <stdio.h>
+#include <math.h>
+
+/*************************** 
+ * IIR filter coefficients *
+ ***************************/ 
+static sIIRCoefficients iir_cf10_11k_11025[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_22k_22050[10] __attribute__((aligned));
+static sIIRCoefficients iir_cforiginal10_44100[10] __attribute__((aligned));
+static sIIRCoefficients iir_cforiginal10_48000[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_44100[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf10_48000[10] __attribute__((aligned));
+static sIIRCoefficients iir_cf15_44100[15] __attribute__((aligned));
+static sIIRCoefficients iir_cf15_48000[15] __attribute__((aligned));
+static sIIRCoefficients iir_cf25_44100[25] __attribute__((aligned));
+static sIIRCoefficients iir_cf25_48000[25] __attribute__((aligned));
+static sIIRCoefficients iir_cf31_44100[31] __attribute__((aligned));
+static sIIRCoefficients iir_cf31_48000[31] __attribute__((aligned));
+
+/****************************************************************** 
+ * Definitions and data structures to calculate the coefficients
+ ******************************************************************/
+static const double band_f011k[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 3000, 4000, 5500 
+};
+static const double band_f022k[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 11000 
+};
+static const double band_f010[] =
+{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000 
+};
+static const double band_original_f010[] =
+{ 60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000 
+};
+static const double band_f015[] =
+{ 25,40,63,100,160,250,400,630,1000,1600,2500,4000,6300,10000,16000
+};
+static const double band_f025[] =
+{ 20,31.5,40,50,80,100,125,160,250,315,400,500,800,
+  1000,1250,1600,2500,3150,4000,5000,8000,10000,12500,16000,20000
+};
+static const double band_f031[] =
+{ 20,25,31.5,40,50,63,80,100,125,160,200,250,315,400,500,630,800,
+  1000,1250,1600,2000,2500,3150,4000,5000,6300,8000,10000,12500,16000,20000
+};
+
+#define GAIN_F0 1.0
+#define GAIN_F1 GAIN_F0 / M_SQRT2
+
+#define SAMPLING_FREQ 44100.0
+#define TETA(f) (2*M_PI*(double)f/bands[n].sfreq)
+#define TWOPOWER(value) (value * value)
+
+#define BETA2(tf0, tf) \
+(TWOPOWER(GAIN_F1)*TWOPOWER(cos(tf0)) \
+ - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+ + TWOPOWER(GAIN_F1) \
+ - TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+#define BETA1(tf0, tf) \
+    (2.0 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf)) \
+     + TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \
+     - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+     - TWOPOWER(GAIN_F1) + TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+#define BETA0(tf0, tf) \
+    (0.25 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \
+     - 0.5 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \
+     + 0.25 * TWOPOWER(GAIN_F1) \
+     - 0.25 * TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf)))
+
+#define GAMMA(beta, tf0) ((0.5 + beta) * cos(tf0))
+#define ALPHA(beta) ((0.5 - beta)/2.0)
+
+struct {
+    sIIRCoefficients *coeffs;
+    const double *cfs;
+    double octave;
+    int band_count;
+    double sfreq;
+} bands[] = {
+  { iir_cf10_11k_11025,     band_f011k,         1.0,     10, 11025.0 },
+  { iir_cf10_22k_22050,     band_f022k,         1.0,     10, 22050.0 },
+  { iir_cforiginal10_44100, band_original_f010, 1.0,     10, 44100.0 },
+  { iir_cforiginal10_48000, band_original_f010, 1.0,     10, 48000.0 },
+  { iir_cf10_44100,         band_f010,          1.0,     10, 44100.0 },
+  { iir_cf10_48000,         band_f010,          1.0,     10, 48000.0 },
+  { iir_cf15_44100,         band_f015,          2.0/3.0, 15, 44100.0 },
+  { iir_cf15_48000,         band_f015,          2.0/3.0, 15, 48000.0 },
+  { iir_cf25_44100,         band_f025,          1.0/3.0, 25, 44100.0 },
+  { iir_cf25_48000,         band_f025,          1.0/3.0, 25, 48000.0 },
+  { iir_cf31_44100,         band_f031,          1.0/3.0, 31, 44100.0 },
+  { iir_cf31_48000,         band_f031,          1.0/3.0, 31, 48000.0 },
+  { 0 }
+};
+
+/*************
+ * Functions *
+ *************/
+
+/* Get the coeffs for a given number of bands and sampling frequency */
+sIIRCoefficients* get_coeffs(gint *bands, gint sfreq, gboolean use_xmms_original_freqs)
+{
+  sIIRCoefficients *iir_cf = 0;
+  switch(sfreq)
+  {
+    case 11025: iir_cf = iir_cf10_11k_11025;
+                *bands = 10;
+                break;
+    case 22050: iir_cf = iir_cf10_22k_22050;
+                *bands = 10;
+                break;
+    case 48000: 
+                switch(*bands)
+                {
+                  case 31: iir_cf = iir_cf31_48000; break;
+                  case 25: iir_cf = iir_cf25_48000; break;
+                  case 15: iir_cf = iir_cf15_48000; break;
+                  default:
+                           iir_cf = use_xmms_original_freqs ? 
+                             iir_cforiginal10_48000 :
+                             iir_cf10_48000;
+                           break;
+                }
+                break;
+    default:
+                switch(*bands)
+                {
+                  case 31: iir_cf = iir_cf31_44100; break;
+                  case 25: iir_cf = iir_cf25_44100; break;
+                  case 15: iir_cf = iir_cf15_44100; break;
+                  default:
+                           iir_cf = use_xmms_original_freqs ? 
+                             iir_cforiginal10_44100 :
+                             iir_cf10_44100;
+                           break;
+                }
+                break;
+  }
+  return iir_cf;
+}
+
+/* Get the freqs at both sides of F0. These will be cut at -3dB */
+static void find_f1_and_f2(double f0, double octave_percent, double *f1, double *f2)
+{
+    double octave_factor = pow(2.0, octave_percent/2.0);
+    *f1 = f0/octave_factor;
+    *f2 = f0*octave_factor;
+}
+
+/* Find the quadratic root
+ * Always return the smallest root */
+static int find_root(double a, double b, double c, double *x0) {
+  double k = c-((b*b)/(4.*a));
+  double h = -(b/(2.*a));
+  double x1 = 0.;
+  if (-(k/a) < 0.)
+    return -1; 
+  *x0 = h - sqrt(-(k/a));
+  x1 = h + sqrt(-(k/a));
+  if (x1 < *x0)
+    *x0 = x1;
+  return 0;
+}
+
+/* Calculate all the coefficients as specified in the bands[] array */
+void calc_coeffs()
+{
+  int i, n;
+  double f1, f2;
+  double x0;
+
+  n = 0;
+  for (; bands[n].cfs; n++) {
+    double *freqs = (double *)bands[n].cfs;
+    for (i=0; i<bands[n].band_count; i++)
+    {
+
+      /* Find -3dB frequencies for the center freq */
+      find_f1_and_f2(freqs[i], bands[n].octave, &f1, &f2);
+      /* Find Beta */
+      if ( find_root(
+            BETA2(TETA(freqs[i]), TETA(f1)), 
+            BETA1(TETA(freqs[i]), TETA(f1)), 
+            BETA0(TETA(freqs[i]), TETA(f1)), 
+            &x0) == 0)
+      {
+        /* Got a solution, now calculate the rest of the factors */
+        /* Take the smallest root always (find_root returns the smallest one)
+         *
+         * NOTE: The IIR equation is
+         *	y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
+         *  Now the 2 factor has been distributed in the coefficients
+         */
+        /* Now store the coefficients */
+        bands[n].coeffs[i].beta = 2.0 * x0;
+        bands[n].coeffs[i].alpha = 2.0 * ALPHA(x0);
+        bands[n].coeffs[i].gamma = 2.0 * GAMMA(x0, TETA(freqs[i]));
+#ifdef DEBUG
+        printf("Freq[%d]: %f. Beta: %.10e Alpha: %.10e Gamma %.10e\n",
+            i, freqs[i], bands[n].coeffs[i].beta,
+            bands[n].coeffs[i].alpha, bands[n].coeffs[i].gamma);
+#endif
+      } else {
+        /* Shouldn't happen */
+        bands[n].coeffs[i].beta = 0.;
+        bands[n].coeffs[i].alpha = 0.;
+        bands[n].coeffs[i].gamma = 0.;
+        printf("  **** Where are the roots?\n");
+      }
+    }// for i
+  }//for n
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/audacious/iir_cfs.h	Sat Jan 14 16:49:00 2006 -0800
@@ -0,0 +1,40 @@
+/*
+ *   PCM time-domain equalizer
+ *
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users.sourceforge.net>
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id: iir_cfs.h,v 1.1 2005/10/17 01:57:59 liebremx Exp $
+ */
+#ifndef IIR_CFS_H
+#define IIR_CFS_H
+
+#include <glib.h>
+
+/* Coefficients entry */
+typedef struct 
+{
+    float beta;
+    float alpha; 
+    float gamma;
+    float dummy; // Word alignment
+}sIIRCoefficients;
+
+sIIRCoefficients* get_coeffs(gint *bands, gint sfreq, 
+                              gboolean use_xmms_original_freqs);
+void calc_coeffs();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/audacious/iir_fpu.c	Sat Jan 14 16:49:00 2006 -0800
@@ -0,0 +1,208 @@
+/*
+ *   PCM time-domain equalizer
+ *
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users sourceforge net>
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id: iir_fpu.c,v 1.3 2005/11/13 20:02:58 lisanet Exp $
+ */
+
+#include <glib.h>
+#include "iir.h"
+#include "iir_fpu.h"
+
+static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+float gain[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
+/* random noise */
+sample_t dither[256];
+gint di;
+
+void set_gain(gint index, gint chn, float val)
+{
+  gain[index][chn] = val;
+}
+
+void clean_history()
+{
+  gint n;
+  /* Zero the history arrays */
+  bzero(data_history, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
+  bzero(data_history2, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
+  /* this is only needed if we use fpu code and there's no other place for
+  the moment to init the dither array*/
+  for (n = 0; n < 256; n++) {
+      dither[n] = (rand() % 4) - 2;
+  }
+  di = 0;
+}
+
+__inline__ int iir(gpointer * d, gint length, gint nch)
+{
+//  FTZ_ON;
+  gint16 *data = (gint16 *) * d;
+  /* Indexes for the history arrays
+   * These have to be kept between calls to this function
+   * hence they are static */
+  static gint i = 2, j = 1, k = 0;	
+
+  gint index, band, channel;
+  gint tempgint, halflength;
+  sample_t out[EQ_CHANNELS], pcm[EQ_CHANNELS];
+
+#if 0
+  // Load the correct filter table according to the sampling rate if needed
+  if (srate != rate)
+  {
+    band_count = eqcfg.band_num;
+    rate = srate;
+    iir_cf = get_coeffs(&band_count, rate, eqcfg.use_xmms_original_freqs);
+    clean_history();
+  }
+#endif
+
+#ifdef BENCHMARK
+  start_counter();
+#endif //BENCHMARK
+
+  /**
+   * IIR filter equation is
+   * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
+   *
+   * NOTE: The 2 factor was introduced in the coefficients to save
+   * 			a multiplication
+   *
+   * This algorithm cascades two filters to get nice filtering
+   * at the expense of extra CPU cycles
+   */
+  /* 16bit, 2 bytes per sample, so divide by two the length of
+   * the buffer (length is in bytes)
+   */
+  halflength = (length >> 1);
+  for (index = 0; index < halflength; index+=nch)
+  {
+    /* For each channel */
+    for (channel = 0; channel < nch; channel++)
+    {
+      pcm[channel] = data[index+channel];
+      /* Preamp gain */
+      pcm[channel] *= preamp[channel];
+      
+      /* add random noise */
+      pcm[channel] += dither[di];
+
+      out[channel] = 0.;
+      /* For each band */
+      for (band = 0; band < band_count; band++)
+      {
+        /* Store Xi(n) */
+        data_history[band][channel].x[i] = pcm[channel];
+        /* Calculate and store Yi(n) */
+        data_history[band][channel].y[i] = 
+          (
+           /* 		= alpha * [x(n)-x(n-2)] */
+           iir_cf[band].alpha * ( data_history[band][channel].x[i]
+             -  data_history[band][channel].x[k])
+           /* 		+ gamma * y(n-1) */
+           + iir_cf[band].gamma * data_history[band][channel].y[j]
+           /* 		- beta * y(n-2) */
+           - iir_cf[band].beta * data_history[band][channel].y[k]
+          );
+        /* 
+         * The multiplication by 2.0 was 'moved' into the coefficients to save
+         * CPU cycles here */
+        /* Apply the gain  */
+        out[channel] +=  data_history[band][channel].y[i]*gain[band][channel]; // * 2.0;
+      } /* For each band */
+
+      if (cfg.eq_extra_filtering)
+      {
+        /* Filter the sample again */
+        for (band = 0; band < band_count; band++)
+        {
+          /* Store Xi(n) */
+          data_history2[band][channel].x[i] = out[channel];
+          /* Calculate and store Yi(n) */
+          data_history2[band][channel].y[i] = 
+            (
+             /* y(n) = alpha * [x(n)-x(n-2)] */
+             iir_cf[band].alpha * (data_history2[band][channel].x[i]
+               -  data_history2[band][channel].x[k])
+             /* 	    + gamma * y(n-1) */
+             + iir_cf[band].gamma * data_history2[band][channel].y[j]
+             /* 		- beta * y(n-2) */
+             - iir_cf[band].beta * data_history2[band][channel].y[k]
+            );
+          /* Apply the gain */
+          out[channel] +=  data_history2[band][channel].y[i]*gain[band][channel];
+        } /* For each band */
+      }
+
+      /* Volume stuff
+         Scale down original PCM sample and add it to the filters 
+         output. This substitutes the multiplication by 0.25
+         Go back to use the floating point multiplication before the
+         conversion to give more dynamic range
+         */
+      out[channel] += pcm[channel]*0.25;
+      
+      /* remove random noise */
+      out[channel] -= dither[di]*0.25;
+
+      /* Round and convert to integer */
+#ifdef ARCH_PPC
+      tempgint = round_ppc(out[channel]);
+#else
+#ifdef ARCH_X86
+      tempgint = round_trick(out[channel]);
+#else
+      tempgint = (int)out[channel];
+#endif
+#endif
+
+      /* Limit the output */
+      if (tempgint < -32768)
+        data[index+channel] = -32768;
+      else if (tempgint > 32767)
+        data[index+channel] = 32767;
+      else 
+        data[index+channel] = tempgint;
+    } /* For each channel */
+    
+    /* Wrap around the indexes */
+    i = (i+1)%3;
+    j = (j+1)%3;
+    k = (k+1)%3;
+    /* random noise index */
+    di = (di + 1) % 256;
+
+  }/* For each pair of samples */
+
+#ifdef BENCHMARK
+  timex += get_counter();
+  blength += length;
+  if (count++ == 1024)
+  {
+    printf("FLOATING POINT: %f %d\n",timex/1024.0, blength/1024);
+    blength = 0;
+    timex = 0.;
+    count = 0;
+  }
+#endif // BENCHMARK
+
+//  FTZ_OFF;
+  return length;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/audacious/iir_fpu.h	Sat Jan 14 16:49:00 2006 -0800
@@ -0,0 +1,39 @@
+/*
+ *   PCM time-domain equalizer
+ *
+ *   Copyright (C) 2002-2005  Felipe Rivera <liebremx at users.sourceforge.net>
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id: iir_fpu.h,v 1.2 2005/11/01 15:59:20 lisanet Exp $$
+ */
+#ifndef IIR_FPU_H
+#define IIR_FPU_H
+
+#define sample_t double
+
+/*
+ * Normal FPU implementation data structures
+ */
+/* Coefficient history for the IIR filter */
+typedef struct
+{
+    sample_t x[3]; /* x[n], x[n-1], x[n-2] */
+    sample_t y[3]; /* y[n], y[n-1], y[n-2] */
+    sample_t dummy1; // Word alignment
+    sample_t dummy2;
+}sXYData;
+
+#endif
--- a/audacious/output.c	Sat Jan 14 11:03:49 2006 -0800
+++ b/audacious/output.c	Sat Jan 14 16:49:00 2006 -0800
@@ -152,9 +152,14 @@
 output_set_eq(gboolean active, gfloat pre, gfloat * bands)
 {
     int i;
-    preamp = 1.0 + 0.0932471 * pre + 0.00279033 * pre * pre;
+    preamp[0] = 1.0 + 0.0932471 * pre + 0.00279033 * pre * pre;
+    preamp[1] = 1.0 + 0.0932471 * pre + 0.00279033 * pre * pre;
+
     for (i = 0; i < 10; ++i)
-        gain[i] = 0.03 * bands[i] + 0.000999999 * bands[i] * bands[i];
+    {
+	set_gain(i, 0, 0.03 * bands[i] + 0.000999999 * bands[i] * bands[i]);
+	set_gain(i, 1, 0.03 * bands[i] + 0.000999999 * bands[i] * bands[i]);
+    }
 }
 
 /* this should be in BYTES, NOT gint16s */
@@ -224,7 +229,7 @@
             ++init;
         }
 
-        iir(&ptr, length);      /*  do iir                  */
+        iir(&ptr, length, nch);
 
         if (swapped)               /* if was swapped          */
             byteswap(length, ptr); /*  swap back for output   */