diff audacious/iir_fpu.c @ 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
children e01a4c8f616f
line wrap: on
line diff
--- /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;
+}