ref: e29dcf169ba38a15396dafcd40e6d405e5d4abd7
parent: 3e7c1e463cc93eb7b8f3aae049a20c6dc1ac3e0b
author: robs <robs>
date: Sat Sep 13 07:59:38 EDT 2008
fft tidy-up
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,16 +28,15 @@
# Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/ /'
set(effects_srcs
- biquad echo noiseprof remix swap
- biquads echos noisered repeat synth
- chorus fade normalise resample tempo
- compand FFT output reverb tremolo
- compandt fft4g pad reverse trim
- contrast filter pan silence vol
- dcshift flanger phaser skeleff
- delay input pitch speed
- dither mcompand polyphas splice
- earwax mixer rate stat
+ biquad earwax mixer polyphas speed
+ biquads echo noiseprof rate splice
+ chorus echos noisered remix stat
+ compand fade normalise repeat swap
+ compandt fft4g output resample synth
+ contrast filter pad reverb tempo
+ dcshift flanger pan reverse tremolo
+ delay input phaser silence trim
+ dither mcompand pitch skeleff vol
)
set(formats_srcs
8svx dat ima-fmt s3-fmt u4-fmt
--- a/src/FFT.c
+++ /dev/null
@@ -1,380 +1,0 @@
-/* libSoX FFT funtions copyright Ian Turner and others.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at
- * your option) any later version.
- *
- * This library 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 Lesser
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * Based on FFT.cpp from Audacity, with the following permission from
- * its author, Dominic Mazzoni (in particular, relicensing the code
- * for use in SoX):
- *
- * I hereby license you under the LGPL all of the code in FFT.cpp
- * from any version of Audacity, with the exception of the windowing
- * function code, as I wrote the rest of the line [sic] that appears
- * in any version of Audacity (or they are derived from Don Cross or
- * NR, which is okay).
- *
- * -- Dominic Mazzoni <dominic@audacityteam.org>, 18th November 2006
- *
- * As regards the windowing function, WindowFunc, Dominic granted a
- * license to it too, writing on the same day:
- *
- * OK, we're good. That's the original version that I wrote, before
- * others contributed.
- *
- * Some of this code was based on a free implementation of an FFT
- * by Don Cross, available on the web at:
- *
- * http://www.intersrv.com/~dcross/fft.html [no longer, it seems]
- *
- * The basic algorithm for his code was based on Numerical Recipes
- * in Fortran.
- */
-
-#include "sox_i.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "FFT.h"
-
-unsigned **gFFTBitTable = NULL;
-const unsigned MaxFastBits = 16;
-
-static int IsPowerOfTwo(unsigned x)
-{
- if (x < 2)
- return 0;
-
- return !(x & (x-1)); /* Thanks to 'byang' for this cute trick! */
-}
-
-static int NumberOfBitsNeeded(unsigned PowerOfTwo)
-{
- int i;
-
- if (PowerOfTwo < 2) {
- sox_fail("Error: FFT called with size %d", PowerOfTwo);
- exit(2);
- }
-
- for (i = 0;; i++)
- if (PowerOfTwo & (1 << i))
- return i;
-}
-
-static unsigned ReverseBits(unsigned index, unsigned NumBits)
-{
- unsigned i, rev;
-
- for (i = rev = 0; i < NumBits; i++) {
- rev = (rev << 1) | (index & 1);
- index >>= 1;
- }
-
- return rev;
-}
-
-
-/* This function permanently allocates about 250Kb (actually (2**16)-2 ints). */
-static void InitFFT(void)
-{
- unsigned len, b;
-
- gFFTBitTable = lsx_calloc(MaxFastBits, sizeof(*gFFTBitTable));
-
- for (b = 1, len = 2; b <= MaxFastBits; b++) {
- unsigned i;
-
- gFFTBitTable[b - 1] = lsx_calloc(len, sizeof(**gFFTBitTable));
- for (i = 0; i < len; i++)
- gFFTBitTable[b - 1][i] = ReverseBits(i, b);
-
- len <<= 1;
- }
-}
-
-#define FastReverseBits(i, NumBits) \
- (NumBits <= MaxFastBits) ? gFFTBitTable[NumBits - 1][i] : ReverseBits(i, NumBits)
-
-/*
- * Complex Fast Fourier Transform
- */
-void FFT(unsigned NumSamples,
- int InverseTransform,
- const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut)
-{
- unsigned i, BlockSize, NumBits; /* Number of bits needed to store indices */
- int j, k, n;
- int BlockEnd;
-
- double angle_numerator = 2.0 * M_PI;
- double tr, ti; /* temp real, temp imaginary */
-
- if (!IsPowerOfTwo(NumSamples)) {
- sox_fail("%d is not a power of two", NumSamples);
- exit(2);
- }
-
- if (!gFFTBitTable)
- InitFFT();
-
- if (InverseTransform)
- angle_numerator = -angle_numerator;
-
- NumBits = NumberOfBitsNeeded(NumSamples);
-
- /*
- ** Do simultaneous data copy and bit-reversal ordering into outputs...
- */
-
- for (i = 0; i < NumSamples; i++) {
- j = FastReverseBits(i, NumBits);
- RealOut[j] = RealIn[i];
- ImagOut[j] = (ImagIn == NULL) ? 0.0 : ImagIn[i];
- }
-
- /*
- ** Do the FFT itself...
- */
-
- BlockEnd = 1;
- for (BlockSize = 2; BlockSize <= NumSamples; BlockSize <<= 1) {
-
- double delta_angle = angle_numerator / (double) BlockSize;
-
- double sm2 = sin(-2 * delta_angle);
- double sm1 = sin(-delta_angle);
- double cm2 = cos(-2 * delta_angle);
- double cm1 = cos(-delta_angle);
- double w = 2 * cm1;
- double ar0, ar1, ar2, ai0, ai1, ai2;
-
- for (i = 0; i < NumSamples; i += BlockSize) {
- ar2 = cm2;
- ar1 = cm1;
-
- ai2 = sm2;
- ai1 = sm1;
-
- for (j = i, n = 0; n < BlockEnd; j++, n++) {
- ar0 = w * ar1 - ar2;
- ar2 = ar1;
- ar1 = ar0;
-
- ai0 = w * ai1 - ai2;
- ai2 = ai1;
- ai1 = ai0;
-
- k = j + BlockEnd;
- tr = ar0 * RealOut[k] - ai0 * ImagOut[k];
- ti = ar0 * ImagOut[k] + ai0 * RealOut[k];
-
- RealOut[k] = RealOut[j] - tr;
- ImagOut[k] = ImagOut[j] - ti;
-
- RealOut[j] += tr;
- ImagOut[j] += ti;
- }
- }
-
- BlockEnd = BlockSize;
- }
-
- /*
- ** Need to normalize if inverse transform...
- */
-
- if (InverseTransform) {
- float denom = (float) NumSamples;
-
- for (i = 0; i < NumSamples; i++) {
- RealOut[i] /= denom;
- ImagOut[i] /= denom;
- }
- }
-}
-
-/*
- * Real Fast Fourier Transform
- *
- * This function was based on the code in Numerical Recipes for C.
- * In Num. Rec., the inner loop is based on a single 1-based array
- * of interleaved real and imaginary numbers. Because we have two
- * separate zero-based arrays, our indices are quite different.
- * Here is the correspondence between Num. Rec. indices and our indices:
- *
- * i1 <-> real[i]
- * i2 <-> imag[i]
- * i3 <-> real[n/2-i]
- * i4 <-> imag[n/2-i]
- */
-
-void RealFFT(unsigned NumSamples, const float *RealIn, float *RealOut, float *ImagOut)
-{
- unsigned i, i3, Half = NumSamples / 2;
- float theta = M_PI / Half;
- float wtemp = (float) sin(0.5 * theta);
- float wpr = -2.0 * wtemp * wtemp;
- float wpi = (float) sin(theta);
- float wr = 1.0 + wpr;
- float wi = wpi;
- float h1r, h1i, h2r, h2i;
- float *tmpReal, *tmpImag;
-
- tmpReal = lsx_calloc(NumSamples, sizeof(float));
- tmpImag = tmpReal + Half;
-
- for (i = 0; i < Half; i++) {
- tmpReal[i] = RealIn[2 * i];
- tmpImag[i] = RealIn[2 * i + 1];
- }
-
- FFT(Half, 0, tmpReal, tmpImag, RealOut, ImagOut);
-
- for (i = 1; i < Half / 2; i++) {
- i3 = Half - i;
-
- h1r = 0.5 * (RealOut[i] + RealOut[i3]);
- h1i = 0.5 * (ImagOut[i] - ImagOut[i3]);
- h2r = 0.5 * (ImagOut[i] + ImagOut[i3]);
- h2i = -0.5 * (RealOut[i] - RealOut[i3]);
-
- RealOut[i] = h1r + wr * h2r - wi * h2i;
- ImagOut[i] = h1i + wr * h2i + wi * h2r;
- RealOut[i3] = h1r - wr * h2r + wi * h2i;
- ImagOut[i3] = -h1i + wr * h2i + wi * h2r;
-
- wtemp = wr;
- wr = wr * wpr - wi * wpi + wr;
- wi = wi * wpr + wtemp * wpi + wi;
- }
-
- h1r = RealOut[0];
- RealOut[0] += ImagOut[0];
- ImagOut[0] = h1r - ImagOut[0];
-
- free(tmpReal);
-}
-
-/*
- * PowerSpectrum
- *
- * This function computes the same as RealFFT, above, but
- * adds the squares of the real and imaginary part of each
- * coefficient, extracting the power and throwing away the
- * phase.
- *
- * For speed, it does not call RealFFT, but duplicates some
- * of its code.
- */
-
-void PowerSpectrum(unsigned NumSamples, const float *In, float *Out)
-{
- unsigned Half, i, i3;
- float theta, wtemp, wpr, wpi, wr, wi;
- float h1r, h1i, h2r, h2i, rt, it;
- float *tmpReal;
- float *tmpImag;
- float *RealOut;
- float *ImagOut;
-
- Half = NumSamples / 2;
-
- theta = M_PI / Half;
-
- tmpReal = lsx_calloc(Half * 4, sizeof(float));
- tmpImag = tmpReal + Half;
- RealOut = tmpImag + Half;
- ImagOut = RealOut + Half;
-
- for (i = 0; i < Half; i++) {
- tmpReal[i] = In[2 * i];
- tmpImag[i] = In[2 * i + 1];
- }
-
- FFT(Half, 0, tmpReal, tmpImag, RealOut, ImagOut);
-
- wtemp = (float) sin(0.5 * theta);
-
- wpr = -2.0 * wtemp * wtemp;
- wpi = (float) sin(theta);
- wr = 1.0 + wpr;
- wi = wpi;
-
- for (i = 1; i < Half / 2; i++) {
-
- i3 = Half - i;
-
- h1r = 0.5 * (RealOut[i] + RealOut[i3]);
- h1i = 0.5 * (ImagOut[i] - ImagOut[i3]);
- h2r = 0.5 * (ImagOut[i] + ImagOut[i3]);
- h2i = -0.5 * (RealOut[i] - RealOut[i3]);
-
- rt = h1r + wr * h2r - wi * h2i;
- it = h1i + wr * h2i + wi * h2r;
-
- Out[i] = rt * rt + it * it;
-
- rt = h1r - wr * h2r + wi * h2i;
- it = -h1i + wr * h2i + wi * h2r;
-
- Out[i3] = rt * rt + it * it;
-
- wr = (wtemp = wr) * wpr - wi * wpi + wr;
- wi = wi * wpr + wtemp * wpi + wi;
- }
-
- rt = (h1r = RealOut[0]) + ImagOut[0];
- it = h1r - ImagOut[0];
- Out[0] = rt * rt + it * it;
-
- rt = RealOut[Half / 2];
- it = ImagOut[Half / 2];
- Out[Half / 2] = rt * rt + it * it;
-
- free(tmpReal);
-}
-
-/*
- * Windowing Functions
- */
-
-void WindowFunc(windowfunc_t whichFunction, int NumSamples, float *in)
-{
- int i;
-
- switch (whichFunction) {
- case BARTLETT:
- for (i = 0; i < NumSamples / 2; i++) {
- in[i] *= (i / (float) (NumSamples / 2));
- in[i + (NumSamples / 2)] *=
- (1.0 - (i / (float) (NumSamples / 2)));
- }
- break;
-
- case HAMMING:
- for (i = 0; i < NumSamples; i++)
- in[i] *= 0.54 - 0.46 * cos(2 * M_PI * i / (NumSamples - 1));
- break;
-
- case HANNING:
- for (i = 0; i < NumSamples; i++)
- in[i] *= 0.50 - 0.50 * cos(2 * M_PI * i / (NumSamples - 1));
- break;
- case RECTANGULAR:
- break;
- }
-}
--- a/src/FFT.h
+++ /dev/null
@@ -1,92 +1,0 @@
-/* libSoX FFT funtions copyright Ian Turner and others.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at
- * your option) any later version.
- *
- * This library 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 Lesser
- * General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- *
- * Based on FFT.h from Audacity, with the following permission from
- * its author, Dominic Mazzoni (in particular, relicensing the code
- * for use in SoX):
- *
- * I hereby license you under the LGPL all of the code in FFT.cpp
- * from any version of Audacity, with the exception of the windowing
- * function code, as I wrote the rest of the line [sic] that appears
- * in any version of Audacity (or they are derived from Don Cross or
- * NR, which is okay).
- *
- * -- Dominic Mazzoni <dominic@audacityteam.org>, 18th November 2006
- *
- * As regards the windowing function, WindowFunc, Dominic granted a
- * license to it too, writing on the same day:
- *
- * OK, we're good. That's the original version that I wrote, before
- * others contributed.
- *
- * Some of this code was based on a free implementation of an FFT
- * by Don Cross, available on the web at:
- *
- * http://www.intersrv.com/~dcross/fft.html [no longer, it seems]
- *
- * The basic algorithm for his code was based on Numerical Recipes
- * in Fortran.
- */
-
-/* aliases */
-#define gFFTBitTable lsx_gFFTBitTable
-#define MaxFastBits lsx_MaxFastBits
-#define FFT lsx_FFT
-#define RealFFT lsx_RealFFT
-#define PowerSpectrum lsx_PowerSpectrum
-#define WindowFunc lsx_WindowFunc
-
-/*
- * This is the function you will use the most often.
- * Given an array of floats, this will compute the power
- * spectrum by doing a Real FFT and then computing the
- * sum of the squares of the real and imaginary parts.
- * Note that the output array is half the length of the
- * input array, and that NumSamples must be a power of two.
- */
-
-void PowerSpectrum(unsigned NumSamples, const float *In, float *Out);
-
-/*
- * Computes an FFT when the input data is real but you still
- * want complex data as output. The output arrays are half
- * the length of the input, and NumSamples must be a power of
- * two.
- */
-
-void RealFFT(unsigned NumSamples,
- const float *RealIn, float *RealOut, float *ImagOut);
-
-/*
- * Computes a FFT of complex input and returns complex output.
- * Currently this is the only function here that supports the
- * inverse transform as well.
- */
-
-void FFT(unsigned NumSamples,
- int InverseTransform,
- const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut);
-
-/*
- * Applies a windowing function to the data in place
- */
-typedef enum {RECTANGULAR, /* no window */
- BARTLETT, /* triangular */
- HAMMING,
- HANNING} windowfunc_t;
-
-void WindowFunc(windowfunc_t whichFunction, int NumSamples, float *data);
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -251,8 +251,8 @@
libsfx_la_SOURCES = \
band.h biquad.c biquad.h biquads.c chorus.c compand.c compandt.c \
compandt.h contrast.c dcshift.c delay.c dither.c earwax.c echo.c \
- echos.c effects.c effects.h effects_i.c fade.c fft4g.c fft4g.h FFT.c \
- FFT.h fifo.h filter.c flanger.c input.c ladspa.c mcompand.c \
+ echos.c effects.c effects.h effects_i.c fade.c fft4g.c fft4g.h \
+ fifo.h filter.c flanger.c input.c ladspa.c mcompand.c \
mixer.c noiseprof.c noisered.c noisered.h normalise.c output.c pad.c \
pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c \
rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \
--- a/src/effects.c
+++ b/src/effects.c
@@ -83,7 +83,7 @@
int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
{
- return effp->handler.getopts(effp, argc, argv);
+ return effp->handler.getopts(effp, argc, (char * *)argv);
} /* sox_effect_options */
/* Effects chain: */
--- a/src/effects_i.c
+++ b/src/effects_i.c
@@ -248,7 +248,7 @@
return result < 0 ? -1 : result;
}
-double bessel_I_0(double x)
+double lsx_bessel_I_0(double x)
{
double term = 1, sum = 1, last_sum, x2 = x / 2;
int i = 1;
@@ -258,3 +258,126 @@
} while (sum != last_sum);
return sum;
}
+
+#include "fft4g.h"
+int * lsx_fft_br;
+double * lsx_fft_sc;
+
+static void update_fft_cache(int len)
+{
+ static int n;
+
+ if (!len) {
+ free(lsx_fft_br);
+ free(lsx_fft_sc);
+ lsx_fft_sc = NULL;
+ lsx_fft_br = NULL;
+ n = 0;
+ return;
+ }
+ if (len > n) {
+ int old_n = n;
+ n = len;
+ lsx_fft_br = lsx_realloc(lsx_fft_br, dft_br_len(n) * sizeof(*lsx_fft_br));
+ lsx_fft_sc = lsx_realloc(lsx_fft_sc, dft_sc_len(n) * sizeof(*lsx_fft_sc));
+ if (!old_n)
+ lsx_fft_br[0] = 0;
+ }
+}
+
+static sox_bool is_power_of_2(int x)
+{
+ return !(x < 2 || (x & (x - 1)));
+}
+
+void lsx_safe_rdft(int len, int type, double * d)
+{
+ assert(is_power_of_2(len));
+ update_fft_cache(len);
+ lsx_rdft(len, type, d, lsx_fft_br, lsx_fft_sc);
+}
+
+void lsx_safe_cdft(int len, int type, double * d)
+{
+ assert(is_power_of_2(len));
+ update_fft_cache(len);
+ lsx_cdft(len, type, d, lsx_fft_br, lsx_fft_sc);
+}
+
+void lsx_power_spectrum(int n, double const * in, double * out)
+{
+ int i;
+ double * work = lsx_memdup(in, n * sizeof(*work));
+ lsx_safe_rdft(n, 1, work);
+ out[0] = sqr(work[0]);
+ for (i = 2; i < n; i += 2)
+ out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]);
+ out[i >> 1] = sqr(work[1]);
+ free(work);
+}
+
+void lsx_power_spectrum_f(int n, float const * in, float * out)
+{
+ int i;
+ double * work = lsx_malloc(n * sizeof(*work));
+ for (i = 0; i< n; ++i) work[i] = in[i];
+ lsx_safe_rdft(n, 1, work);
+ out[0] = sqr(work[0]);
+ for (i = 2; i < n; i += 2)
+ out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]);
+ out[i >> 1] = sqr(work[1]);
+ free(work);
+}
+
+void lsx_apply_hann_f(float h[], const int num_points)
+{
+ int i, m = num_points - 1;
+ for (i = 0; i < num_points; ++i) {
+ double x = 2 * M_PI * i / m;
+ h[i] *= .5 - .5 * cos(x);
+ }
+}
+
+void lsx_apply_hann(double h[], const int num_points)
+{
+ int i, m = num_points - 1;
+ for (i = 0; i < num_points; ++i) {
+ double x = 2 * M_PI * i / m;
+ h[i] *= .5 - .5 * cos(x);
+ }
+}
+
+void lsx_apply_hamming(double h[], const int num_points)
+{
+ int i, m = num_points - 1;
+ for (i = 0; i < num_points; ++i) {
+ double x = 2 * M_PI * i / m;
+ h[i] *= .53836 - .46164 * cos(x);
+ }
+}
+
+void lsx_apply_bartlett(double h[], const int num_points)
+{
+ int i, m = num_points - 1;
+ for (i = 0; i < num_points; ++i) {
+ h[i] *= 2. / m * (m / 2. - fabs(i - m / 2.));
+ }
+}
+
+double lsx_kaiser_beta(double att)
+{
+ if (att > 100 ) return .1117 * att - 1.11;
+ if (att > 50 ) return .1102 * (att - 8.7);
+ if (att > 20.96) return .58417 * pow(att -20.96, .4) + .07886 * (att - 20.96);
+ return 0;
+}
+
+void lsx_apply_kaiser(double h[], const int num_points, double beta)
+{
+ int i, m = num_points - 1;
+ for (i = 0; i <= m; ++i) {
+ double x = 2. * i / m - 1;
+ h[i] *= lsx_bessel_I_0(beta * sqrt(1 - x * x)) / lsx_bessel_I_0(beta);
+ }
+}
+
--- a/src/fft4g.c
+++ b/src/fft4g.c
@@ -291,12 +291,19 @@
#define cos cosf
#define atan atanf
- #define cdft cdft_f
- #define rdft rdft_f
- #define ddct ddct_f
- #define ddst ddst_f
- #define dfct dfct_f
- #define dfst dfst_f
+ #define cdft lsx_cdft_f
+ #define rdft lsx_rdft_f
+ #define ddct lsx_ddct_f
+ #define ddst lsx_ddst_f
+ #define dfct lsx_dfct_f
+ #define dfst lsx_dfst_f
+#else
+ #define cdft lsx_cdft
+ #define rdft lsx_rdft
+ #define ddct lsx_ddct
+ #define ddst lsx_ddst
+ #define dfct lsx_dfct
+ #define dfst lsx_dfst
#endif
static void bitrv2conj(int n, int *ip, double *a);
--- a/src/fft4g.h
+++ b/src/fft4g.h
@@ -13,19 +13,19 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-void cdft(int, int, double *, int *, double *);
-void rdft(int, int, double *, int *, double *);
-void ddct(int, int, double *, int *, double *);
-void ddst(int, int, double *, int *, double *);
-void dfct(int, double *, double *, int *, double *);
-void dfst(int, double *, double *, int *, double *);
+void lsx_cdft(int, int, double *, int *, double *);
+void lsx_rdft(int, int, double *, int *, double *);
+void lsx_ddct(int, int, double *, int *, double *);
+void lsx_ddst(int, int, double *, int *, double *);
+void lsx_dfct(int, double *, double *, int *, double *);
+void lsx_dfst(int, double *, double *, int *, double *);
-void cdft_f(int, int, float *, int *, float *);
-void rdft_f(int, int, float *, int *, float *);
-void ddct_f(int, int, float *, int *, float *);
-void ddst_f(int, int, float *, int *, float *);
-void dfct_f(int, float *, float *, int *, float *);
-void dfst_f(int, float *, float *, int *, float *);
+void lsx_cdft_f(int, int, float *, int *, float *);
+void lsx_rdft_f(int, int, float *, int *, float *);
+void lsx_ddct_f(int, int, float *, int *, float *);
+void lsx_ddst_f(int, int, float *, int *, float *);
+void lsx_dfct_f(int, float *, float *, int *, float *);
+void lsx_dfst_f(int, float *, float *, int *, float *);
#define dft_br_len(l) (2 + (1 << (int)(log(l / 2 + .5) / log(2.)) / 2))
#define dft_sc_len(l) (l / 2)
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -95,7 +95,7 @@
float *out = lsx_calloc(FREQCOUNT, sizeof(float));
int i;
- PowerSpectrum(WINDOWSIZE, chan->window, out);
+ lsx_power_spectrum_f(WINDOWSIZE, chan->window, out);
for (i = 0; i < FREQCOUNT; i ++) {
if (out[i] > 0) {
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -31,6 +31,28 @@
size_t bufdata;
} priv_t;
+static void FFT(unsigned NumSamples,
+ int InverseTransform,
+ const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut)
+{
+ unsigned i;
+ double * work = malloc(2 * NumSamples * sizeof(*work));
+ for (i = 0; i < 2 * NumSamples; i += 2) {
+ work[i] = RealIn[i >> 1];
+ work[i + 1] = ImagIn? ImagIn[i >> 1] : 0;
+ }
+ lsx_safe_cdft(2 * (int)NumSamples, InverseTransform? -1 : 1, work);
+ if (InverseTransform) for (i = 0; i < 2 * NumSamples; i += 2) {
+ RealOut[i >> 1] = work[i] / NumSamples;
+ ImagOut[i >> 1] = work[i + 1] / NumSamples;
+ }
+ else for (i = 0; i < 2 * NumSamples; i += 2) {
+ RealOut[i >> 1] = work[i];
+ ImagOut[i >> 1] = work[i + 1];
+ }
+ free(work);
+}
+
/*
* Get the options. Default file is stdin (if the audio
* input file isn't coming from there, of course!)
@@ -146,8 +168,8 @@
FFT(WINDOWSIZE, 0, inr, NULL, outr, outi);
memcpy(inr, window, WINDOWSIZE*sizeof(float));
- WindowFunc(HANNING, WINDOWSIZE, inr);
- PowerSpectrum(WINDOWSIZE, inr, power);
+ lsx_apply_hann_f(inr, WINDOWSIZE);
+ lsx_power_spectrum_f(WINDOWSIZE, inr, power);
for (i = 0; i < FREQCOUNT; i ++) {
float smooth;
@@ -189,7 +211,7 @@
}
FFT(WINDOWSIZE, 1, outr, outi, inr, ini);
- WindowFunc(HANNING, WINDOWSIZE, inr);
+ lsx_apply_hann_f(inr, WINDOWSIZE);
memcpy(window, inr, WINDOWSIZE*sizeof(float));
--- a/src/noisered.h
+++ b/src/noisered.h
@@ -19,8 +19,6 @@
*/
#include "sox_i.h"
-#include "FFT.h"
-
#include <math.h>
#define WINDOWSIZE 2048
--- a/src/rate.c
+++ b/src/rate.c
@@ -143,7 +143,7 @@
fifo_trim_by(output_fifo, (f->dft_length + overlap) >> 1);
memcpy(output, input, f->dft_length * sizeof(*output));
- rdft(f->dft_length, 1, output, s->bit_rev_table, s->sin_cos_table);
+ lsx_rdft(f->dft_length, 1, output, s->bit_rev_table, s->sin_cos_table);
output[0] *= f->coefs[0];
output[1] *= f->coefs[1];
for (i = 2; i < f->dft_length; i += 2) {
@@ -151,7 +151,7 @@
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1];
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1];
}
- rdft(f->dft_length, -1, output, s->bit_rev_table, s->sin_cos_table);
+ lsx_rdft(f->dft_length, -1, output, s->bit_rev_table, s->sin_cos_table);
for (j = 1, i = 2; i < f->dft_length - overlap; ++j, i += 2)
output[j] = output[i];
@@ -176,7 +176,7 @@
for (j = i = 0; i < f->dft_length; ++j, i += 2)
output[i] = input[j], output[i+1] = 0;
- rdft(f->dft_length, 1, output, s->bit_rev_table, s->sin_cos_table);
+ lsx_rdft(f->dft_length, 1, output, s->bit_rev_table, s->sin_cos_table);
output[0] *= f->coefs[0];
output[1] *= f->coefs[1];
for (i = 2; i < f->dft_length; i += 2) {
@@ -184,7 +184,7 @@
output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1];
output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1];
}
- rdft(f->dft_length, -1, output, s->bit_rev_table, s->sin_cos_table);
+ lsx_rdft(f->dft_length, -1, output, s->bit_rev_table, s->sin_cos_table);
}
}
@@ -196,7 +196,7 @@
for (i = 0; i <= m / 2; ++i) {
double x = M_PI * (i - .5 * m), y = 2. * i / m - 1;
h[i] = x? sin(Fc * x) / x : Fc;
- sum += h[i] *= bessel_I_0(beta * sqrt(1 - y * y));
+ sum += h[i] *= lsx_bessel_I_0(beta * sqrt(1 - y * y));
if (m - i != i)
sum += h[m - i] = h[i];
}
@@ -254,19 +254,19 @@
work = calloc(work_len, sizeof(*work));
for (i = 0; i < *len; ++i) work[i] = (*h)[i];
- rdft(work_len, 1, work, p->bit_rev_table, p->sin_cos_table); /* Cepstrum: */
+ lsx_rdft(work_len, 1, work, p->bit_rev_table, p->sin_cos_table); /* Cepstrum: */
work[0] = log(fabs(work[0])), work[1] = log(fabs(work[1]));
for (i = 2; i < work_len; i += 2) {
work[i] = log(sqrt(sqr(work[i]) + sqr(work[i + 1])));
work[i + 1] = 0;
}
- rdft(work_len, -1, work, p->bit_rev_table, p->sin_cos_table);
+ lsx_rdft(work_len, -1, work, p->bit_rev_table, p->sin_cos_table);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
for (i = 1; i < work_len / 2; ++i) { /* Window to reject acausal components */
work[i] *= 2;
work[i + work_len / 2] = 0;
}
- rdft(work_len, 1, work, p->bit_rev_table, p->sin_cos_table);
+ lsx_rdft(work_len, 1, work, p->bit_rev_table, p->sin_cos_table);
/* Some DFTs require phase unwrapping here, but rdft seems not to. */
for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */
@@ -278,7 +278,7 @@
work[i ] = x * cos(work[i + 1]);
work[i + 1] = x * sin(work[i + 1]);
}
- rdft(work_len, -1, work, p->bit_rev_table, p->sin_cos_table);
+ lsx_rdft(work_len, -1, work, p->bit_rev_table, p->sin_cos_table);
for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len;
for (i = 1; i < work_len; ++i) if (work[i] > work[peak]) /* Find peak. */
@@ -359,7 +359,7 @@
p->bit_rev_table = calloc(dft_br_len(dft_length),sizeof(*p->bit_rev_table));
p->sin_cos_table = calloc(dft_sc_len(dft_length),sizeof(*p->sin_cos_table));
}
- rdft(dft_length, 1, f->coefs, p->bit_rev_table, p->sin_cos_table);
+ lsx_rdft(dft_length, 1, f->coefs, p->bit_rev_table, p->sin_cos_table);
}
#include "rate_filters.h"
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -61,7 +61,19 @@
unsigned lsx_gcd(unsigned a, unsigned b);
unsigned lsx_lcm(unsigned a, unsigned b);
-double bessel_I_0(double x);
+double lsx_bessel_I_0(double x);
+extern int * lsx_fft_br;
+extern double * lsx_fft_sc;
+void lsx_safe_rdft(int len, int type, double * d);
+void lsx_safe_cdft(int len, int type, double * d);
+void lsx_power_spectrum(int n, double const * in, double * out);
+void lsx_power_spectrum_f(int n, float const * in, float * out);
+void lsx_apply_hann_f(float h[], const int num_points);
+void lsx_apply_hann(double h[], const int num_points);
+void lsx_apply_hamming(double h[], const int num_points);
+void lsx_apply_bartlett(double h[], const int num_points);
+double lsx_kaiser_beta(double att);
+void lsx_apply_kaiser(double h[], const int num_points, double beta);
#ifndef HAVE_STRCASECMP
int strcasecmp(const char *s1, const char *s2);
--- a/src/spectrogram.c
+++ b/src/spectrogram.c
@@ -40,49 +40,6 @@
#define MAX_DFT_SIZE (DFT_BASE_SIZE << MAX_DFT_SIZE_SHIFT)
#define MAX_COLS 999 /* Also max seconds */
-static void apply_hann(double h[], const int num_points)
-{
- int i, m = num_points - 1;
- for (i = 0; i < num_points; ++i) {
- double x = 2 * M_PI * i / m;
- h[i] *= .5 - .5 * cos(x);
- }
-}
-
-static void apply_hamming(double h[], const int num_points)
-{
- int i, m = num_points - 1;
- for (i = 0; i < num_points; ++i) {
- double x = 2 * M_PI * i / m;
- h[i] *= .53836 - .46164 * cos(x);
- }
-}
-
-static void apply_bartlett(double h[], const int num_points)
-{
- int i, m = num_points - 1;
- for (i = 0; i < num_points; ++i) {
- h[i] *= 2. / m * (m / 2. - fabs(i - m / 2.));
- }
-}
-
-static double kaiser_beta(double att)
-{
- if (att > 100 ) return .1117 * att - 1.11;
- if (att > 50 ) return .1102 * (att - 8.7);
- if (att > 20.96) return .58417 * pow(att -20.96, .4) + .07886 * (att - 20.96);
- return 0;
-}
-
-static void apply_kaiser(double h[], const int num_points, double beta)
-{
- int i, m = num_points - 1;
- for (i = 0; i <= m; ++i) {
- double x = 2. * i / m - 1;
- h[i] *= bessel_I_0(beta * sqrt(1 - x * x)) / bessel_I_0(beta);
- }
-}
-
typedef enum {Window_Hann, Window_Hamming, Window_Bartlett, Window_Rectangular, Window_Kaiser} win_type_t;
static enum_item const window_options[] = {
ENUM_ITEM(Window_,Hann)
@@ -178,11 +135,11 @@
if (end) memset(p->window, 0, sizeof(p->window));
for (i = 0; i < n; ++i) w[i] = 1;
switch (p->win_type) {
- case Window_Hann: apply_hann(w, n); break;
- case Window_Hamming: apply_hamming(w, n); break;
- case Window_Bartlett: apply_bartlett(w, n); break;
+ case Window_Hann: lsx_apply_hann(w, n); break;
+ case Window_Hamming: lsx_apply_hamming(w, n); break;
+ case Window_Bartlett: lsx_apply_bartlett(w, n); break;
case Window_Rectangular: break;
- default: apply_kaiser(w, n, kaiser_beta(p->dB_range + 20.));
+ default: lsx_apply_kaiser(w, n, lsx_kaiser_beta(p->dB_range + 20.));
}
for (i = 0; i < p->dft_size; ++i) sum += p->window[i];
for (i = 0; i < p->dft_size; ++i) p->window[i] *= 2 / sum
@@ -265,7 +222,7 @@
if ((p->end = max(p->end, p->end_min)) != p->last_end)
make_window(p, p->last_end = p->end);
for (i = 0; i < p->dft_size; ++i) p->dft_buf[i] = p->buf[i] * p->window[i];
- rdft(p->dft_size, 1, p->dft_buf, p->bit_rev_table, p->sin_cos_table);
+ lsx_rdft(p->dft_size, 1, p->dft_buf, p->bit_rev_table, p->sin_cos_table);
p->magnitudes[0] += sqr(p->dft_buf[0]);
for (i = 1; i < p->dft_size >> 1; ++i)
p->magnitudes[i] += sqr(p->dft_buf[2*i]) + sqr(p->dft_buf[2*i+1]);
--- a/src/stat.c
+++ b/src/stat.c
@@ -15,7 +15,6 @@
#include "sox_i.h"
#include <string.h>
-#include "FFT.h"
/* Private data for stat effect */
typedef struct {
@@ -105,7 +104,7 @@
if (stat->fft) {
stat->fft_offset = 0;
stat->re_in = lsx_malloc(sizeof(float) * stat->fft_size);
- stat->re_out = lsx_malloc(sizeof(float) * (stat->fft_size / 2));
+ stat->re_out = lsx_malloc(sizeof(float) * (stat->fft_size / 2 + 1));
}
return SOX_SUCCESS;
@@ -119,8 +118,8 @@
float ffa = rate / samples;
unsigned i;
- PowerSpectrum(samples, re_in, re_out);
- for (i = 0; i < samples / 2; i++)
+ lsx_power_spectrum_f((int)samples, re_in, re_out);
+ for (i = 0; i < samples / 2; i++) /* FIXME: should be <= samples / 2 */
fprintf(stderr, "%f %f\n", ffa * i, re_out[i]);
}