aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/qmmp/equ/iir.h1
-rw-r--r--src/qmmp/equ/iir_fpu.c148
-rw-r--r--src/qmmp/output.cpp9
3 files changed, 156 insertions, 2 deletions
diff --git a/src/qmmp/equ/iir.h b/src/qmmp/equ/iir.h
index a85dfc0bf..77a398414 100644
--- a/src/qmmp/equ/iir.h
+++ b/src/qmmp/equ/iir.h
@@ -58,6 +58,7 @@ void set_preamp(int chn, float val);
int iir(void * d, int length, int nch);
+int iir32(void * d, int length, int nch);
#ifdef ARCH_X86
__inline__ int round_trick(float floatvalue_to_round);
diff --git a/src/qmmp/equ/iir_fpu.c b/src/qmmp/equ/iir_fpu.c
index 1d79b95a1..6740d3a88 100644
--- a/src/qmmp/equ/iir_fpu.c
+++ b/src/qmmp/equ/iir_fpu.c
@@ -205,3 +205,151 @@ __inline__ int iir(void * d, int length, int nch)
// FTZ_OFF;
return length;
}
+
+__inline__ int iir32(void * d, int length, int nch)
+{
+// FTZ_ON;
+ int *data = (int *) d;
+ /* Indexes for the history arrays
+ * These have to be kept between calls to this function
+ * hence they are static */
+ static int i = 2, j = 1, k = 0;
+
+ int index, band, channel;
+ int tempgint, quaterlength;
+ sample_t out[EQ_CHANNELS], pcm[EQ_CHANNELS];
+
+ // 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();
+ }*/
+
+#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
+ */
+ /* 32bit, 4 bytes per sample, so divide by four the length of
+ * the buffer (length is in bytes)
+ */
+ quaterlength = (length >> 2);
+ for (index = 0; index < quaterlength; 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 (eqcfg.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
+ 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;
+}
diff --git a/src/qmmp/output.cpp b/src/qmmp/output.cpp
index 84f51610b..876d5a652 100644
--- a/src/qmmp/output.cpp
+++ b/src/qmmp/output.cpp
@@ -309,7 +309,12 @@ void Output::run()
if (b)
{
if (m_useEq)
- iir((void*) b->data, b->nbytes, m_channels);
+ {
+ if(m_format == Qmmp::PCM_S16LE)
+ iir((void*) b->data, b->nbytes, m_channels);
+ else if(m_format == Qmmp::PCM_S32LE || m_format == Qmmp::PCM_S24LE)
+ iir32((void*) b->data, b->nbytes, m_channels);
+ }
dispatchVisual(b);
if (SoftwareVolume::instance())
SoftwareVolume::instance()->changeVolume(b, m_channels, m_format);
@@ -394,7 +399,7 @@ void Output::updateEqSettings()
set_gain(i,1, 0.03*value+0.000999999*value*value);
}
if(isRunning())
- m_useEq = m_eqEnabled && m_format == Qmmp::PCM_S16LE;
+ m_useEq = m_eqEnabled;// && m_format == Qmmp::PCM_S16LE;
mutex()->unlock();
}