shithub: aubio

Download patch

ref: aadd27aa7e4ebb2e420472b537f8231dbd4568c8
parent: f1eda562f9859b371d8f3425494ebf14a4ab3d2e
author: Paul Brossier <piem@piem.org>
date: Wed Nov 7 11:30:29 EST 2007

fft.c,fft.h: refactorised, no more mfft, only one fft

--- a/src/fft.c
+++ b/src/fft.c
@@ -18,7 +18,8 @@
 */
 
 #include "aubio_priv.h"
-#include "sample.h"
+#include "fvec.h"
+#include "cvec.h"
 #include "mathutils.h"
 #include "fft.h"
 
@@ -40,31 +41,34 @@
 #endif
 
 struct _aubio_fft_t {
-  uint_t fft_size;
+  uint_t winsize;
   uint_t channels;
-  real_t    *in, *out;
-  fft_data_t   *specdata;
+  uint_t fft_size;
+  real_t *in, *out;
   fftw_plan   pfw, pbw;
+  fft_data_t * specdata;     /* complex spectral data */
+  fvec_t * compspec;
 };
 
-static void aubio_fft_getspectrum(fft_data_t * spectrum, smpl_t *norm, smpl_t * phas, uint_t size);
-
-aubio_fft_t * new_aubio_fft(uint_t size) {
+aubio_fft_t * new_aubio_fft(uint_t winsize, uint_t channels) {
   aubio_fft_t * s = AUBIO_NEW(aubio_fft_t);
+  s->winsize  = winsize;
+  s->channels = channels;
   /* allocate memory */
-  s->in       = AUBIO_ARRAY(real_t,size);
-  s->out      = AUBIO_ARRAY(real_t,size);
+  s->in       = AUBIO_ARRAY(real_t,winsize);
+  s->out      = AUBIO_ARRAY(real_t,winsize);
+  s->compspec = new_fvec(winsize,channels);
   /* create plans */
 #ifdef HAVE_COMPLEX_H
-  s->fft_size = size/2+1;
+  s->fft_size = winsize/2+1;
   s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
-  s->pfw = fftw_plan_dft_r2c_1d(size, s->in,  s->specdata, FFTW_ESTIMATE);
-  s->pbw = fftw_plan_dft_c2r_1d(size, s->specdata, s->out, FFTW_ESTIMATE);
+  s->pfw = fftw_plan_dft_r2c_1d(winsize, s->in,  s->specdata, FFTW_ESTIMATE);
+  s->pbw = fftw_plan_dft_c2r_1d(winsize, s->specdata, s->out, FFTW_ESTIMATE);
 #else
-  s->fft_size = size;
+  s->fft_size = winsize;
   s->specdata = (fft_data_t*)fftw_malloc(sizeof(fft_data_t)*s->fft_size);
-  s->pfw = fftw_plan_r2r_1d(size, s->in,  s->specdata, FFTW_R2HC, FFTW_ESTIMATE);
-  s->pbw = fftw_plan_r2r_1d(size, s->specdata, s->out, FFTW_HC2R, FFTW_ESTIMATE);
+  s->pfw = fftw_plan_r2r_1d(winsize, s->in,  s->specdata, FFTW_R2HC, FFTW_ESTIMATE);
+  s->pbw = fftw_plan_r2r_1d(winsize, s->specdata, s->out, FFTW_HC2R, FFTW_ESTIMATE);
 #endif
   return s;
 }
@@ -71,6 +75,7 @@
 
 void del_aubio_fft(aubio_fft_t * s) {
   /* destroy data */
+  del_fvec(s->compspec);
   fftw_destroy_plan(s->pfw);
   fftw_destroy_plan(s->pbw);
   fftw_free(s->specdata);
@@ -79,117 +84,111 @@
   AUBIO_FREE(s);
 }
 
-void aubio_fft_do(const aubio_fft_t * s, 
-    const smpl_t * data, fft_data_t * spectrum, const uint_t size) {
-  uint_t i;
-  for (i=0;i<size;i++) s->in[i] = data[i];
-  fftw_execute(s->pfw);
-  for (i=0; i < s->fft_size; i++) spectrum[i] = s->specdata[i];
+void aubio_fft_do(aubio_fft_t * s, fvec_t * input, cvec_t * spectrum) {
+  aubio_fft_do_complex(s, input, s->compspec);
+  aubio_fft_get_spectrum(s->compspec, spectrum);
 }
 
-void aubio_fft_rdo(const aubio_fft_t * s, 
-    const fft_data_t * spectrum, smpl_t * data, const uint_t size) {
-  uint_t i;
-  const smpl_t renorm = 1./(smpl_t)size;
-  for (i=0; i < s->fft_size; i++) s->specdata[i] = spectrum[i];
-  fftw_execute(s->pbw);
-  for (i=0;i<size;i++) data[i] = s->out[i]*renorm;
+void aubio_fft_rdo(aubio_fft_t * s, cvec_t * spectrum, fvec_t * output) {
+  aubio_fft_get_realimag(spectrum, s->compspec);
+  aubio_fft_rdo_complex(s, s->compspec, output);
 }
 
-#ifdef HAVE_COMPLEX_H
-
-void aubio_fft_getnorm(smpl_t * norm, fft_data_t * spectrum, uint_t size) {
-  uint_t i;
-  for (i=0;i<size/2+1;i++) norm[i] = ABSC(spectrum[i]);
+void aubio_fft_do_complex(aubio_fft_t * s, fvec_t * input, fvec_t * compspec) {
+  uint_t i, j;
+  for (i = 0; i < s->channels; i++) {
+    for (j=0; j < s->winsize; j++) {
+      s->in[j] = input->data[i][j];
+    }
+    fftw_execute(s->pfw);
+#if HAVE_COMPLEX_H
+    compspec->data[i][0] = REAL(s->specdata[0]);
+    for (j = 1; j < s->fft_size -1 ; j++) {
+      compspec->data[i][j] = REAL(s->specdata[j]);
+      compspec->data[i][compspec->length - j] = IMAG(s->specdata[j]);
+    }
+    compspec->data[i][s->fft_size-1] = REAL(s->specdata[s->fft_size-1]);
+#else
+    for (j = 0; j < s->fft_size; j++) {
+      compspec->data[i][j] = s->specdata[j];
+    }
+#endif
+  }
 }
 
-void aubio_fft_getphas(smpl_t * phas, fft_data_t * spectrum, uint_t size) {
-  uint_t i;
-  for (i=0;i<size/2+1;i++) phas[i] = ARGC(spectrum[i]);
-}
-
-void aubio_fft_getspectrum(fft_data_t * spectrum, smpl_t *norm, smpl_t * phas, uint_t size) {
-  uint_t j;
-  for (j=0; j<size/2+1; j++) {
-    spectrum[j]  = CEXPC(I*phas[j]);
-    spectrum[j] *= norm[j];
+void aubio_fft_rdo_complex(aubio_fft_t * s, fvec_t * compspec, fvec_t * output) {
+  uint_t i, j;
+  const smpl_t renorm = 1./(smpl_t)s->winsize;
+  for (i = 0; i < compspec->channels; i++) {
+#if HAVE_COMPLEX_H
+    s->specdata[0] = compspec->data[i][0];
+    for (j=1; j < s->fft_size - 1; j++) {
+      s->specdata[j] = compspec->data[i][j] + 
+        I * compspec->data[i][compspec->length - j];
+    }
+    s->specdata[s->fft_size - 1] = compspec->data[i][s->fft_size - 1];
+#else
+    for (j=0; j < s->fft_size; j++) {
+      s->specdata[j] = compspec->data[i][j];
+    }
+#endif
+    fftw_execute(s->pbw);
+    for (j = 0; j < output->length; j++) {
+      output->data[i][j] = s->out[j]*renorm;
+    }
   }
 }
 
-#else
-
-void aubio_fft_getnorm(smpl_t * norm, fft_data_t * spectrum, uint_t size) {
-  uint_t i;
-  norm[0] = spectrum[0];
-  for (i=1;i<size/2;i++) norm[i] = SQRT((SQR(spectrum[i]) + SQR(spectrum[size-i])));
-  norm[size/2] = spectrum[size/2];
+void aubio_fft_get_spectrum(fvec_t * compspec, cvec_t * spectrum) {
+  aubio_fft_get_phas(compspec, spectrum);
+  aubio_fft_get_norm(compspec, spectrum);
 }
 
-void aubio_fft_getphas(smpl_t * phas, fft_data_t * spectrum, uint_t size) {
-  uint_t i;
-  phas[0] = 0;
-  for (i=1;i<size/2+1;i++) phas[i] = atan2f(spectrum[size-i] , spectrum[i]);
-  phas[size/2] = 0;
+void aubio_fft_get_realimag(cvec_t * spectrum, fvec_t * compspec) {
+  aubio_fft_get_imag(spectrum, compspec);
+  aubio_fft_get_real(spectrum, compspec);
 }
 
-void aubio_fft_getspectrum(fft_data_t * spectrum, smpl_t *norm, smpl_t * phas, uint_t size) {
-  uint_t j;
-  for (j=0; j<size/2+1; j++) {
-    spectrum[j]       = norm[j]*COS(phas[j]);
+void aubio_fft_get_phas(fvec_t * compspec, cvec_t * spectrum) {
+  uint_t i, j;
+  for (i = 0; i < spectrum->channels; i++) {
+    spectrum->phas[i][0] = 0.;
+    for (j=1; j < spectrum->length - 1; j++) {
+      spectrum->phas[i][j] = atan2f(compspec->data[i][compspec->length-j],
+          compspec->data[i][j]);
+    }
+    spectrum->phas[i][spectrum->length-1] = 0.;
   }
-  for (j=1; j<size/2+1; j++) {
-    spectrum[size-j]  = norm[j]*SIN(phas[j]);
-  }
 }
 
-#endif
-
-/* new interface aubio_mfft */
-struct _aubio_mfft_t {
-        aubio_fft_t * fft;      /* fftw interface */
-        fft_data_t ** spec;     /* complex spectral data */
-        uint_t winsize;
-        uint_t channels;
-};
-
-aubio_mfft_t * new_aubio_mfft(uint_t winsize, uint_t channels){
-  uint_t i;
-  aubio_mfft_t * fft = AUBIO_NEW(aubio_mfft_t);
-  fft->winsize       = winsize;
-  fft->channels      = channels;
-  fft->fft           = new_aubio_fft(winsize);
-  fft->spec          = AUBIO_ARRAY(fft_data_t*,channels);
-  for (i=0; i < channels; i++)
-    fft->spec[i] = AUBIO_ARRAY(fft_data_t,winsize);
-  return fft;
-}
-
-/* execute stft */
-void aubio_mfft_do (aubio_mfft_t * fft,fvec_t * in,cvec_t * fftgrain){
-  uint_t i=0;
-  /* execute stft */
-  for (i=0; i < fft->channels; i++) {
-    aubio_fft_do (fft->fft,in->data[i],fft->spec[i],fft->winsize);
-    /* put norm and phase into fftgrain */
-    aubio_fft_getnorm(fftgrain->norm[i], fft->spec[i], fft->winsize);
-    aubio_fft_getphas(fftgrain->phas[i], fft->spec[i], fft->winsize);
+void aubio_fft_get_norm(fvec_t * compspec, cvec_t * spectrum) {
+  uint_t i, j = 0;
+  for (i = 0; i < spectrum->channels; i++) {
+    spectrum->norm[i][0] = compspec->data[i][0];
+    for (j=1; j < spectrum->length - 1; j++) {
+      spectrum->norm[i][j] = SQRT(SQR(compspec->data[i][j]) 
+          + SQR(compspec->data[i][compspec->length - j]) );
+    }
+    spectrum->norm[i][spectrum->length-1] = compspec->data[i][compspec->length/2];
   }
 }
 
-/* execute inverse fourier transform */
-void aubio_mfft_rdo(aubio_mfft_t * fft,cvec_t * fftgrain, fvec_t * out){
-  uint_t i=0;
-  for (i=0; i < fft->channels; i++) {
-    aubio_fft_getspectrum(fft->spec[i],fftgrain->norm[i],fftgrain->phas[i],fft->winsize);
-    aubio_fft_rdo(fft->fft,fft->spec[i],out->data[i],fft->winsize);
+void aubio_fft_get_imag(cvec_t * spectrum, fvec_t * compspec) {
+  uint_t i, j;
+  for (i = 0; i < compspec->channels; i++) {
+    for (j = 1; j < compspec->length / 2 + 1; j++) {
+      compspec->data[i][compspec->length - j] =
+        spectrum->norm[i][j]*SIN(spectrum->phas[i][j]);
+    }
   }
 }
 
-void del_aubio_mfft(aubio_mfft_t * fft) {
-  uint_t i;
-  for (i=0; i < fft->channels; i++)
-    AUBIO_FREE(fft->spec[i]);
-  AUBIO_FREE(fft->spec);
-  del_aubio_fft(fft->fft);
-  AUBIO_FREE(fft);        
+void aubio_fft_get_real(cvec_t * spectrum, fvec_t * compspec) {
+  uint_t i, j;
+  for (i = 0; i < compspec->channels; i++) {
+    for (j = 0; j< compspec->length / 2 + 1; j++) {
+      compspec->data[i][j] = 
+        spectrum->norm[i][j]*COS(spectrum->phas[i][j]);
+    }
+  }
 }
--- a/src/fft.h
+++ b/src/fft.h
@@ -66,9 +66,10 @@
 /** create new FFT computation object
 
   \param size length of the FFT
+  \param channels number of channels
 
 */
-aubio_fft_t * new_aubio_fft(uint_t size);
+aubio_fft_t * new_aubio_fft(uint_t size, uint_t channels);
 /** delete FFT object 
 
   \param s fft object as returned by new_aubio_fft
@@ -75,84 +76,88 @@
 
 */
 void del_aubio_fft(aubio_fft_t * s);
+
 /** compute forward FFT
 
   \param s fft object as returned by new_aubio_fft
-  \param data input signal 
+  \param input input signal 
   \param spectrum output spectrum 
-  \param size length of the input vector 
 
 */
-void aubio_fft_do (const aubio_fft_t *s, const smpl_t * data,
-    fft_data_t * spectrum, const uint_t size);
+void aubio_fft_do (aubio_fft_t *s, fvec_t * input, cvec_t * spectrum);
 /** compute backward (inverse) FFT
 
   \param s fft object as returned by new_aubio_fft
   \param spectrum input spectrum 
-  \param data output signal 
-  \param size length of the input vector 
+  \param output output signal 
 
 */
-void aubio_fft_rdo(const aubio_fft_t *s, const fft_data_t * spectrum,
-    smpl_t * data, const uint_t size);
-/** compute norm vector from input spectrum
+void aubio_fft_rdo (aubio_fft_t *s, cvec_t * spectrum, fvec_t * output);
 
-  \param norm magnitude vector output
-  \param spectrum spectral data input
-  \param size size of the vectors
+/** compute forward FFT
 
+  \param s fft object as returned by new_aubio_fft
+  \param input real input signal 
+  \param compspec complex output fft real/imag
+
 */
-void aubio_fft_getnorm(smpl_t * norm, fft_data_t * spectrum, uint_t size);
-/** compute phase vector from input spectrum 
- 
-  \param phase phase vector output
-  \param spectrum spectral data input
-  \param size size of the vectors
+void aubio_fft_do_complex (aubio_fft_t *s, fvec_t * input, fvec_t * compspec);
+/** compute backward (inverse) FFT from real/imag
 
+  \param s fft object as returned by new_aubio_fft
+  \param compspec real/imag input fft array 
+  \param output real output array 
+
 */
-void aubio_fft_getphas(smpl_t * phase, fft_data_t * spectrum, uint_t size);
+void aubio_fft_rdo_complex (aubio_fft_t *s, fvec_t * compspec, fvec_t * output);
 
-/** FFT object (using cvec)
+/** convert real/imag spectrum to norm/phas spectrum 
 
-  This object works similarly as aubio_fft_t, except the spectral data is
-  stored in a cvec_t as two vectors, magnitude and phase. 
+  \param compspec real/imag input fft array 
+  \param spectrum cvec norm/phas output array 
 
 */
-typedef struct _aubio_mfft_t aubio_mfft_t;
+void aubio_fft_get_spectrum(fvec_t * compspec, cvec_t * spectrum);
+/** convert real/imag spectrum to norm/phas spectrum 
 
-/** create new FFT computation object
+  \param compspec real/imag input fft array 
+  \param spectrum cvec norm/phas output array 
 
-  \param winsize length of the FFT
-  \param channels number of channels 
-
 */
-aubio_mfft_t * new_aubio_mfft(uint_t winsize, uint_t channels);
-/** compute forward FFT
+void aubio_fft_get_realimag(cvec_t * spectrum, fvec_t * compspec);
 
-  \param fft fft object as returned by new_aubio_mfft
-  \param in input signal 
-  \param fftgrain output spectrum
+/** compute phas spectrum from real/imag parts 
 
+  \param compspec real/imag input fft array 
+  \param spectrum cvec norm/phas output array 
+
 */
-void aubio_mfft_do (aubio_mfft_t * fft,fvec_t * in,cvec_t * fftgrain);
-/** compute backward (inverse) FFT
+void aubio_fft_get_phas(fvec_t * compspec, cvec_t * spectrum);
+/** compute imaginary part from the norm/phas cvec 
 
-  \param fft fft object as returned by new_aubio_mfft
-  \param fftgrain input spectrum (cvec) 
-  \param out output signal 
+  \param spectrum norm/phas input array 
+  \param compspec real/imag output fft array 
 
 */
-void aubio_mfft_rdo(aubio_mfft_t * fft,cvec_t * fftgrain, fvec_t * out);
-/** delete FFT object 
+void aubio_fft_get_imag(cvec_t * spectrum, fvec_t * compspec);
 
-  \param fft fft object as returned by new_aubio_mfft
+/** compute norm component from real/imag parts 
 
+  \param compspec real/imag input fft array 
+  \param spectrum cvec norm/phas output array 
+
 */
-void del_aubio_mfft(aubio_mfft_t * fft);
+void aubio_fft_get_norm(fvec_t * compspec, cvec_t * spectrum);
+/** compute real part from norm/phas components 
 
+  \param spectrum norm/phas input array 
+  \param compspec real/imag output fft array 
 
+*/
+void aubio_fft_get_real(cvec_t * spectrum, fvec_t * compspec);
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif
+#endif // FFT_H_