Mercurial > audlegacy
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 */