shithub: aubio

Download patch

ref: f218f29b032d1e2390a9be25dfd633732b6bd9f1
parent: ef7df7698cf744f3d43859eb304e4ea4d69d4bfa
parent: 4368223876c6727ac7a181f6e7f0ae9adfadf563
author: Paul Brossier <piem@piem.org>
date: Wed Nov 7 12:03:59 EST 2007

merge from banane

--- 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_
--- a/src/hist.c
+++ b/src/hist.c
@@ -1,20 +1,20 @@
 /*
-	 Copyright (C) 2003 Paul Brossier
+   Copyright (C) 2003 Paul Brossier
 
-	 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 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.
+   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.
-	 */
+   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.
+*/
 
 #include "aubio_priv.h"
 #include "sample.h"
@@ -27,12 +27,11 @@
  */
 
 struct _aubio_hist_t {
-	/*bug: move to a fvec */
-	smpl_t ** hist;
-	uint_t nelems;
-	uint_t channels;
-	smpl_t * cent;
-	aubio_scale_t *scaler;
+  fvec_t * hist;
+  uint_t nelems;
+  uint_t channels;
+  fvec_t * cent;
+  aubio_scale_t *scaler;
 };
 
 /**
@@ -39,134 +38,120 @@
  * Object creation/deletion calls
  */
 aubio_hist_t * new_aubio_hist (smpl_t ilow, smpl_t ihig, uint_t nelems, uint_t channels){
-	aubio_hist_t * s = AUBIO_NEW(aubio_hist_t);
-	smpl_t step = (ihig-ilow)/(smpl_t)(nelems);
-	smpl_t accum = step;
-	uint_t i;
-	s->channels = channels;
-	s->nelems = nelems;
-	s->hist = AUBIO_ARRAY(smpl_t*, channels);
-	for (i=0; i< s->channels; i++) {
-		s->hist[i] = AUBIO_ARRAY(smpl_t, nelems);
-	}
-	s->cent = AUBIO_ARRAY(smpl_t, nelems);
-	
-	/* use scale to map ilow/ihig -> 0/nelems */
-	s->scaler = new_aubio_scale(ilow,ihig,0,nelems);
-	/* calculate centers now once */
-	s->cent[0] = ilow + 0.5 * step;
-	for (i=1; i < s->nelems; i++, accum+=step )
-		s->cent[i] = s->cent[0] + accum;
-	
-	return s;	
+  aubio_hist_t * s = AUBIO_NEW(aubio_hist_t);
+  smpl_t step = (ihig-ilow)/(smpl_t)(nelems);
+  smpl_t accum = step;
+  uint_t i;
+  s->channels = channels;
+  s->nelems = nelems;
+  s->hist = new_fvec(nelems, channels);
+  s->cent = new_fvec(nelems, 1);
+
+  /* use scale to map ilow/ihig -> 0/nelems */
+  s->scaler = new_aubio_scale(ilow,ihig,0,nelems);
+  /* calculate centers now once */
+  s->cent->data[0][0] = ilow + 0.5 * step;
+  for (i=1; i < s->nelems; i++, accum+=step )
+    s->cent->data[0][i] = s->cent->data[0][0] + accum;
+
+  return s;
 }
 
 void del_aubio_hist(aubio_hist_t *s) {
-	uint_t i;
-	for (i=0; i< s->channels; i++) {
-		AUBIO_FREE(s->hist[i]);
-	}
-	AUBIO_FREE(s->hist);
-	AUBIO_FREE(s->cent);
-	del_aubio_scale(s->scaler);
-	AUBIO_FREE(s);
+  del_fvec(s->hist);
+  del_fvec(s->cent);
+  del_aubio_scale(s->scaler);
+  AUBIO_FREE(s);
 }
 
 /***
  * do it
  */
-void aubio_hist_do (aubio_hist_t *s, fvec_t *input) 
-{
-	uint_t i,j;
-	sint_t tmp = 0;
-	aubio_scale_do(s->scaler, input);
-	/* reset data */
-	for (i=0; i < s->channels; i++)
-		for (j=0; j < s->nelems; j++) 
-			s->hist[i][j] = 0;
-	/* run accum */
-	for (i=0; i < input->channels; i++)
-		for (j=0;  j < input->length; j++)
-		{
-			tmp = (sint_t)FLOOR(input->data[i][j]);
-			if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
-				s->hist[i][tmp] += 1;
-		}
+void aubio_hist_do (aubio_hist_t *s, fvec_t *input) {
+  uint_t i,j;
+  sint_t tmp = 0;
+  aubio_scale_do(s->scaler, input);
+  /* reset data */
+  for (i=0; i < s->channels; i++)
+    for (j=0; j < s->nelems; j++)
+      s->hist->data[i][j] = 0;
+  /* run accum */
+  for (i=0; i < input->channels; i++)
+    for (j=0;  j < input->length; j++)
+    {
+      tmp = (sint_t)FLOOR(input->data[i][j]);
+      if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+        s->hist->data[i][tmp] += 1;
+    }
 }
 
-void aubio_hist_do_notnull (aubio_hist_t *s, fvec_t *input) 
-{
-	uint_t i,j;
-	sint_t tmp = 0;
-	aubio_scale_do(s->scaler, input);
-	/* reset data */
-	for (i=0; i < s->channels; i++)
-		for (j=0; j < s->nelems; j++) 
-			s->hist[i][j] = 0;
-	/* run accum */
-	for (i=0; i < input->channels; i++)
-		for (j=0;  j < input->length; j++) 
-		{
-			if (input->data[i][j] != 0) {
-				tmp = (sint_t)FLOOR(input->data[i][j]);
-				if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
-					s->hist[i][tmp] += 1;
-			}
-		}
+void aubio_hist_do_notnull (aubio_hist_t *s, fvec_t *input) {
+  uint_t i,j;
+  sint_t tmp = 0;
+  aubio_scale_do(s->scaler, input);
+  /* reset data */
+  for (i=0; i < s->channels; i++)
+    for (j=0; j < s->nelems; j++)
+      s->hist->data[i][j] = 0;
+  /* run accum */
+  for (i=0; i < input->channels; i++)
+    for (j=0;  j < input->length; j++) {
+      if (input->data[i][j] != 0) {
+        tmp = (sint_t)FLOOR(input->data[i][j]);
+        if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+          s->hist->data[i][tmp] += 1;
+      }
+    }
 }
 
 
-void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input) 
-{
-	uint_t i,j;
-	sint_t tmp = 0;
-	smpl_t ilow = vec_min(input);
-	smpl_t ihig = vec_max(input);
-	smpl_t step = (ihig-ilow)/(smpl_t)(s->nelems);
-	
-	/* readapt */
-	aubio_scale_set(s->scaler, ilow, ihig, 0, s->nelems);
+void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input) {
+  uint_t i,j;
+  sint_t tmp = 0;
+  smpl_t ilow = vec_min(input);
+  smpl_t ihig = vec_max(input);
+  smpl_t step = (ihig-ilow)/(smpl_t)(s->nelems);
 
-	/* recalculate centers */
-	s->cent[0] = ilow + 0.5f * step;
-	for (i=1; i < s->nelems; i++)
-		s->cent[i] = s->cent[0] + i * step;
+  /* readapt */
+  aubio_scale_set(s->scaler, ilow, ihig, 0, s->nelems);
 
-	/* scale */	
-	aubio_scale_do(s->scaler, input);
+  /* recalculate centers */
+  s->cent->data[0][0] = ilow + 0.5f * step;
+  for (i=1; i < s->nelems; i++)
+    s->cent->data[0][i] = s->cent->data[0][0] + i * step;
 
-	/* reset data */
-	for (i=0; i < s->channels; i++)
-		for (j=0; j < s->nelems; j++) 
-			s->hist[i][j] = 0;
-	/* run accum */
-	for (i=0; i < input->channels; i++)
-		for (j=0;  j < input->length; j++) 
-		{
-			if (input->data[i][j] != 0) {
-				tmp = (sint_t)FLOOR(input->data[i][j]);
-				if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
-					s->hist[i][tmp] += 1;
-			}
-		}
+  /* scale */
+  aubio_scale_do(s->scaler, input);
+
+  /* reset data */
+  for (i=0; i < s->channels; i++)
+    for (j=0; j < s->nelems; j++)
+      s->hist->data[i][j] = 0;
+  /* run accum */
+  for (i=0; i < input->channels; i++)
+    for (j=0;  j < input->length; j++) {
+      if (input->data[i][j] != 0) {
+        tmp = (sint_t)FLOOR(input->data[i][j]);
+        if ((tmp >= 0) && (tmp < (sint_t)s->nelems))
+          s->hist->data[i][tmp] += 1;
+      }
+    }
 }
 
-void aubio_hist_weigth (aubio_hist_t *s) 
-{
-	uint_t i,j;
-	for (i=0; i < s->channels; i++)
-		for (j=0; j < s->nelems; j++) {
-			s->hist[i][j] *= s->cent[j];
-		}
+void aubio_hist_weight (aubio_hist_t *s) {
+  uint_t i,j;
+  for (i=0; i < s->channels; i++)
+    for (j=0; j < s->nelems; j++) {
+      s->hist->data[i][j] *= s->cent->data[0][j];
+    }
 }
 
-smpl_t aubio_hist_mean (aubio_hist_t *s) 
-{
-	uint_t i,j;
-	smpl_t tmp = 0.0f;
-	for (i=0; i < s->channels; i++)
-		for (j=0; j < s->nelems; j++)
-			tmp += s->hist[i][j];
-	return tmp/(smpl_t)(s->nelems);
+smpl_t aubio_hist_mean (aubio_hist_t *s) {
+  uint_t i,j;
+  smpl_t tmp = 0.0f;
+  for (i=0; i < s->channels; i++)
+    for (j=0; j < s->nelems; j++)
+      tmp += s->hist->data[i][j];
+  return tmp/(smpl_t)(s->nelems);
 }
 
--- a/src/hist.h
+++ b/src/hist.h
@@ -1,21 +1,22 @@
 /*
-	 Copyright (C) 2003 Paul Brossier
+   Copyright (C) 2003 Paul Brossier
 
-	 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 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.
+   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.
-	 */
+   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.
 
+*/
+
 /** @file
  *
  * Histogram function
@@ -33,11 +34,11 @@
 /** histogram object */
 typedef struct _aubio_hist_t aubio_hist_t;
 
-/** histogram creation 
+/** histogram creation
  * \param flow minimum input
  * \param fhig maximum input
  * \param nelems number of histogram columns
- * \param channels number of channels 
+ * \param channels number of channels
  */
 aubio_hist_t * new_aubio_hist(smpl_t flow, smpl_t fhig, uint_t nelems, uint_t channels);
 /** histogram deletion */
@@ -47,9 +48,9 @@
 /** compute the histogram ignoring null elements */
 void aubio_hist_do_notnull(aubio_hist_t *s, fvec_t * input);
 /** compute the mean of the histogram */
-smpl_t aubio_hist_mean(aubio_hist_t *s); 
+smpl_t aubio_hist_mean(aubio_hist_t *s);
 /** weight the histogram */
-void aubio_hist_weigth(aubio_hist_t *s); 
+void aubio_hist_weight(aubio_hist_t *s);
 /** compute dynamic histogram for non-null elements */
 void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input);
 
--- a/src/onsetdetection.c
+++ b/src/onsetdetection.c
@@ -128,7 +128,7 @@
 		/* apply o->histogram */
 		aubio_hist_dyn_notnull(o->histog,o->dev1);
 		/* weight it */
-		aubio_hist_weigth(o->histog);
+		aubio_hist_weight(o->histog);
 		/* its mean is the result */
 		onset->data[i][0] = aubio_hist_mean(o->histog);	
 		//onset->data[i][0] = vec_mean(o->dev1);
@@ -157,7 +157,7 @@
 		 * overall function)*/
 		aubio_hist_dyn_notnull(o->histog,o->dev1);
 		/* weight it */
-		aubio_hist_weigth(o->histog);
+		aubio_hist_weight(o->histog);
 		/* its mean is the result */
 		onset->data[i][0] = aubio_hist_mean(o->histog);	
 
--- a/src/phasevoc.c
+++ b/src/phasevoc.c
@@ -18,7 +18,8 @@
 */
 
 #include "aubio_priv.h"
-#include "sample.h"
+#include "fvec.h"
+#include "cvec.h"
 #include "fft.h"
 #include "mathutils.h"
 #include "phasevoc.h"
@@ -28,12 +29,12 @@
   uint_t win_s;       /** grain length */
   uint_t hop_s;       /** overlap step */
   uint_t channels;    /** number of channels */
-  aubio_mfft_t * fft; /** spectral data */
-  fvec_t * synth;     /**cur output grain [win_s] */
-  fvec_t * synthold;  /**last input frame [win_s-hop_s] */
-  fvec_t * data;      /**current input grain [win_s] */
-  fvec_t * dataold;   /**last input frame [win_s-hop_s] */
-  smpl_t * w;          /** grain window [win_s] */
+  aubio_fft_t * fft;  /** fft object */
+  fvec_t * synth;     /** cur output grain [win_s] */
+  fvec_t * synthold;  /** last input frame [win_s-hop_s] */
+  fvec_t * data;      /** current input grain [win_s] */
+  fvec_t * dataold;   /** last input frame [win_s-hop_s] */
+  smpl_t * w;         /** grain window [win_s] */
 };
 
 
@@ -57,13 +58,13 @@
   /* shift */
   vec_shift(pv->data);
   /* calculate fft */
-  aubio_mfft_do (pv->fft,pv->data,fftgrain);
+  aubio_fft_do (pv->fft,pv->data,fftgrain);
 }
 
 void aubio_pvoc_rdo(aubio_pvoc_t *pv,cvec_t * fftgrain, fvec_t * synthnew) {
   uint_t i;
   /* calculate rfft */
-  aubio_mfft_rdo(pv->fft,fftgrain,pv->synth);
+  aubio_fft_rdo(pv->fft,fftgrain,pv->synth);
   /* unshift */
   vec_shift(pv->synth);
   for (i=0; i<pv->channels; i++) {
@@ -87,7 +88,7 @@
     hop_s = win_s / 2;
   }
 
-  pv->fft      = new_aubio_mfft(win_s,channels);
+  pv->fft      = new_aubio_fft(win_s,channels);
 
   /* remember old */
   pv->data     = new_fvec (win_s, channels);
@@ -111,7 +112,7 @@
   del_fvec(pv->synth);
   del_fvec(pv->dataold);
   del_fvec(pv->synthold);
-  del_aubio_mfft(pv->fft);
+  del_aubio_fft(pv->fft);
   AUBIO_FREE(pv->w);
   AUBIO_FREE(pv);
 }
--- a/src/pitchfcomb.c
+++ b/src/pitchfcomb.c
@@ -38,7 +38,7 @@
 	fvec_t * win;
         cvec_t * fftOut;
         fvec_t * fftLastPhase;
-	aubio_mfft_t * fft;
+	aubio_fft_t * fft;
         //aubio_pvoc_t * pvoc;
 };
 
@@ -51,7 +51,7 @@
   p->winput       = new_fvec(bufsize,1);
   p->fftOut       = new_cvec(bufsize,1);
   p->fftLastPhase = new_fvec(bufsize,1);
-  p->fft = new_aubio_mfft(bufsize, 1);
+  p->fft = new_aubio_fft(bufsize, 1);
   p->win = new_fvec(bufsize,1);
   aubio_window(p->win->data[0], bufsize, aubio_win_hanning);
   return p;
@@ -73,7 +73,7 @@
   for (k=0; k < input->length; k++){
 	  p->winput->data[0][k] = p->win->data[0][k] * input->data[0][k];
   }
-  aubio_mfft_do(p->fft,p->winput,p->fftOut);
+  aubio_fft_do(p->fft,p->winput,p->fftOut);
 
   for (k=0; k<=p->fftSize/2; k++) {
     smpl_t
@@ -129,7 +129,7 @@
   del_fvec(p->fftLastPhase);
   del_fvec(p->win);
   del_fvec(p->winput);
-  del_aubio_mfft(p->fft);
+  del_aubio_fft(p->fft);
   AUBIO_FREE(p);
 }
 
--- a/src/pitchyinfft.c
+++ b/src/pitchyinfft.c
@@ -30,7 +30,7 @@
   fvec_t * sqrmag;    /**< square difference function */
   fvec_t * weight;    /**< spectral weighting window (psychoacoustic model) */
   cvec_t * fftout;    /**< Fourier transform output */
-  aubio_mfft_t * fft; /**< fft object to compute square difference function */
+  aubio_fft_t * fft; /**< fft object to compute square difference function */
   fvec_t * yinfft;    /**< Yin function */
 };
 
@@ -48,7 +48,7 @@
 {
   aubio_pitchyinfft_t * p = AUBIO_NEW(aubio_pitchyinfft_t);
   p->winput       = new_fvec(bufsize,1);
-  p->fft          = new_aubio_mfft(bufsize, 1);
+  p->fft          = new_aubio_fft(bufsize, 1);
   p->fftout       = new_cvec(bufsize,1);
   p->sqrmag       = new_fvec(bufsize,1);
   p->res          = new_cvec(bufsize,1);
@@ -96,7 +96,7 @@
   for (l=0; l < input->length; l++){
 	  p->winput->data[0][l] = p->win->data[0][l] * input->data[0][l];
   }
-  aubio_mfft_do(p->fft,p->winput,p->fftout);
+  aubio_fft_do(p->fft,p->winput,p->fftout);
   for (l=0; l < p->fftout->length; l++){
 	  p->sqrmag->data[0][l] = SQR(p->fftout->norm[0][l]);
 	  p->sqrmag->data[0][l] *= p->weight->data[0][l]; 
@@ -111,7 +111,7 @@
 	  sum += p->sqrmag->data[0][l];
   }
   sum *= 2.;
-  aubio_mfft_do(p->fft,p->sqrmag,res);
+  aubio_fft_do(p->fft,p->sqrmag,res);
   yin->data[0][0] = 1.; 
   for (tau=1; tau < yin->length; tau++) {
 	  yin->data[0][tau] = sum -
@@ -142,7 +142,7 @@
 
 void del_aubio_pitchyinfft(aubio_pitchyinfft_t *p){
 	del_fvec(p->win);
-	del_aubio_mfft(p->fft);
+	del_aubio_fft(p->fft);
 	del_fvec(p->yinfft);
 	del_fvec(p->sqrmag);
 	del_cvec(p->res);
--- a/src/scale.c
+++ b/src/scale.c
@@ -1,19 +1,20 @@
 /*
-	 Copyright (C) 2003 Paul Brossier
+   Copyright (C) 2003 Paul Brossier
 
-	 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 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.
+   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.
+   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.
+
 */
 
 #include "aubio_priv.h"
@@ -21,56 +22,58 @@
 #include "scale.h"
 
 struct _aubio_scale_t {
-	smpl_t ilow;
-	smpl_t ihig;
-	smpl_t olow;
-	smpl_t ohig;
+  smpl_t ilow;
+  smpl_t ihig;
+  smpl_t olow;
+  smpl_t ohig;
 
-	smpl_t scaler;
-	smpl_t irange;
-	
-	/* not implemented yet : type in/out data
-	bool inint;
-	bool outint;
-	*/
+  smpl_t scaler;
+  smpl_t irange;
+
+  /* not implemented yet : type in/out data
+     bool inint;
+     bool outint;
+     */
 };
 
-aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig, smpl_t olow, smpl_t ohig	){
-	aubio_scale_t * s = AUBIO_NEW(aubio_scale_t);
-	aubio_scale_set (s, ilow, ihig, olow, ohig);
-	return s;	
+aubio_scale_t * new_aubio_scale (smpl_t ilow, smpl_t ihig, 
+    smpl_t olow, smpl_t ohig) {
+  aubio_scale_t * s = AUBIO_NEW(aubio_scale_t);
+  aubio_scale_set (s, ilow, ihig, olow, ohig);
+  return s;
 }
 
 void del_aubio_scale(aubio_scale_t *s) {
-	AUBIO_FREE(s);
+  AUBIO_FREE(s);
 }
 
-void aubio_scale_set (aubio_scale_t *s, smpl_t ilow, smpl_t ihig, smpl_t olow, smpl_t ohig) 
-{
-	smpl_t inputrange = ihig - ilow;
-	smpl_t outputrange= ohig - olow;
-	s->ilow = ilow;
-	s->ihig = ihig;
-	s->olow = olow;
-	s->ohig = ohig;
-	if (inputrange == 0 )
-		s->scaler = 0.0f;
-	else {
-		s->scaler = outputrange/inputrange;
-		if (inputrange < 0 )
-			inputrange = inputrange * -1.0f;
-	}
+void aubio_scale_set (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+    smpl_t olow, smpl_t ohig) {
+  smpl_t inputrange = ihig - ilow;
+  smpl_t outputrange= ohig - olow;
+  s->ilow = ilow;
+  s->ihig = ihig;
+  s->olow = olow;
+  s->ohig = ohig;
+  if (inputrange == 0) {
+    s->scaler = 0.0f;
+  } else {
+    s->scaler = outputrange/inputrange;
+    if (inputrange < 0) {
+      inputrange = inputrange * -1.0f;
+    }
+  }
 }
 
 void aubio_scale_do (aubio_scale_t *s, fvec_t *input) 
 {
-	uint_t i, j;
-	for (i=0; i < input->channels; i++){
-		for (j=0;  j < input->length; j++){
-			input->data[i][j] -= s->ilow;
-			input->data[i][j] *= s->scaler;
-			input->data[i][j] += s->olow;
-		}
-	}
+  uint_t i, j;
+  for (i=0; i < input->channels; i++){
+    for (j=0;  j < input->length; j++){
+      input->data[i][j] -= s->ilow;
+      input->data[i][j] *= s->scaler;
+      input->data[i][j] += s->olow;
+    }
+  }
 }
 
--- a/src/scale.h
+++ b/src/scale.h
@@ -1,19 +1,19 @@
 /*
-	 Copyright (C) 2003 Paul Brossier
+   Copyright (C) 2003 Paul Brossier
 
-	 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 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.
+   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.
+   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.
 */
 
 /** \file
@@ -44,7 +44,8 @@
   \param ihig higher value of output function
 
 */
-aubio_scale_t * new_aubio_scale(smpl_t flow, smpl_t fhig, smpl_t ilow, smpl_t ihig	);
+aubio_scale_t * new_aubio_scale(smpl_t flow, smpl_t fhig,
+    smpl_t ilow, smpl_t ihig);
 /** delete a scale object 
 
   \param s scale object as returned by new_aubio_scale
@@ -67,7 +68,8 @@
   \param ihig higher value of output function
 
 */
-void aubio_scale_set (aubio_scale_t *s, smpl_t ilow, smpl_t ihig, smpl_t olow, smpl_t ohig);
+void aubio_scale_set (aubio_scale_t *s, smpl_t ilow, smpl_t ihig,
+    smpl_t olow, smpl_t ohig);
 
 #ifdef __cplusplus
 }
--- a/swig/aubio.i
+++ b/swig/aubio.i
@@ -71,15 +71,19 @@
 extern uint_t aubio_sndfile_samplerate(aubio_sndfile_t * file);
 
 /* fft */
-extern void aubio_fft_getnorm(smpl_t * norm, fft_data_t * spectrum, uint_t size);
-extern void aubio_fft_getphas(smpl_t * phase, fft_data_t * spectrum, uint_t size);
+extern aubio_fft_t * new_aubio_fft(uint_t size, uint_t channels);
+extern void del_aubio_fft(aubio_fft_t * s);
+extern void aubio_fft_do (aubio_fft_t *s, fvec_t * input, cvec_t * spectrum);
+extern void aubio_fft_rdo (aubio_fft_t *s, cvec_t * spectrum, fvec_t * output);
+extern void aubio_fft_do_complex (aubio_fft_t *s, fvec_t * input, fvec_t * compspec);
+extern void aubio_fft_rdo_complex (aubio_fft_t *s, fvec_t * compspec, fvec_t * output);
+extern void aubio_fft_get_spectrum(fvec_t * compspec, cvec_t * spectrum);
+extern void aubio_fft_get_realimag(cvec_t * spectrum, fvec_t * compspec);
+extern void aubio_fft_get_phas(fvec_t * compspec, cvec_t * spectrum);
+extern void aubio_fft_get_imag(cvec_t * spectrum, fvec_t * compspec);
+extern void aubio_fft_get_norm(fvec_t * compspec, cvec_t * spectrum);
+extern void aubio_fft_get_real(cvec_t * spectrum, fvec_t * compspec);
 
-extern aubio_mfft_t * new_aubio_mfft(uint_t winsize, uint_t channels);
-extern void aubio_mfft_do (aubio_mfft_t * fft,fvec_t * in,cvec_t * fftgrain);
-extern void aubio_mfft_rdo(aubio_mfft_t * fft,cvec_t * fftgrain, fvec_t * out);
-extern void del_aubio_mfft(aubio_mfft_t * fft);
-
-
 /* filter */
 extern aubio_filter_t * new_aubio_filter(uint_t samplerate, uint_t order);
 extern aubio_filter_t * new_aubio_adsgn_filter(uint_t samplerate);
@@ -100,7 +104,9 @@
 extern void del_aubio_hist(aubio_hist_t *s);
 extern void aubio_hist_do(aubio_hist_t *s, fvec_t * input);
 extern void aubio_hist_do_notnull(aubio_hist_t *s, fvec_t * input);
-extern void aubio_hist_dyn_notnull (aubio_hist_t *s, fvec_t *input);
+extern void aubio_hist_dyn_notnull(aubio_hist_t *s, fvec_t *input);
+extern void aubio_hist_weight(aubio_hist_t *s);
+extern smpl_t aubio_hist_mean(aubio_hist_t *s);
 
 /* mathutils */
 typedef enum {
--- a/tests/python/fft.py
+++ b/tests/python/fft.py
@@ -1,47 +1,46 @@
-import unittest
 import math
 
+from template import aubio_unit_template
+
 from aubio.aubiowrapper import *
 
-buf_size = 8092 
+buf_size = 1024
 channels = 4
 
-precision = 6
+class fft_unit(aubio_unit_template):
 
-class aubio_mfft_test_case(unittest.TestCase):
-
   def setUp(self):
-    self.o = new_aubio_mfft(buf_size, channels)
+    self.o = new_aubio_fft(buf_size, channels)
 
   def tearDown(self):
-    del_aubio_mfft(self.o)
+    del_aubio_fft(self.o)
 
   def test_create(self):
     """ test creation and deletion of fft object """
     pass
 
-  def test_aubio_mfft_do_zeroes(self):
-    """ test aubio_mfft_do on zeroes """
+  def test_do_zeroes(self):
+    """ test aubio_fft_do on zeroes """
     input    = new_fvec(buf_size, channels)
     fftgrain = new_cvec(buf_size, channels)
     for index in range(buf_size):
       for channel in range(channels):
-        self.assertEqual(0., fvec_read_sample(input, channel, index))
-    aubio_mfft_do(self.o, input, fftgrain)
+        self.assertCloseEnough(0., fvec_read_sample(input, channel, index))
+    aubio_fft_do(self.o, input, fftgrain)
     for index in range(buf_size/2+1):
       for channel in range(channels):
-        self.assertEqual(0., cvec_read_norm(fftgrain, channel, index))
+        self.assertCloseEnough(0., cvec_read_norm(fftgrain, channel, index))
     for index in range(buf_size/2+1):
       for channel in range(channels):
-        self.assertEqual(0., cvec_read_phas(fftgrain, channel, index))
+        self.assertCloseEnough(0., cvec_read_phas(fftgrain, channel, index))
     del fftgrain
     del input
 
-  def test_aubio_mfft_rdo_zeroes(self):
-    """ test aubio_mfft_rdo on zeroes """
+  def test_rdo_zeroes(self):
+    """ test aubio_fft_rdo on zeroes """
     fftgrain = new_cvec(buf_size, channels)
     output    = new_fvec(buf_size, channels)
-    aubio_mfft_rdo(self.o, fftgrain, output)
+    aubio_fft_rdo(self.o, fftgrain, output)
     # check output
     for index in range(buf_size):
       for channel in range(channels):
@@ -49,17 +48,17 @@
     del fftgrain
     del output
 
-  def test_aubio_mfft_do_impulse(self):
-    """ test aubio_mfft_do with an impulse on one channel """
+  def test_do_impulse(self):
+    """ test aubio_fft_do with an impulse on one channel """
     input    = new_fvec(buf_size, channels)
     fftgrain = new_cvec(buf_size, channels)
     # write impulse in channel 0, sample 0.
     some_constant = 0.3412432456
     fvec_write_sample(input, some_constant, 0, 0)
-    aubio_mfft_do(self.o, input, fftgrain)
+    aubio_fft_do(self.o, input, fftgrain)
     # check norm
     for index in range(buf_size/2+1):
-      self.assertAlmostEqual(some_constant, cvec_read_norm(fftgrain, 0, index), precision)
+      self.assertCloseEnough(some_constant, cvec_read_norm(fftgrain, 0, index))
     for index in range(buf_size/2+1):
       for channel in range(1, channels):
         self.assertEqual(0., cvec_read_norm(fftgrain, channel, index))
@@ -70,8 +69,8 @@
     del fftgrain
     del input
 
-  def test_aubio_mfft_do_constant(self):
-    """ test aubio_mfft_do with a constant on one channel """
+  def test_do_constant(self):
+    """ test aubio_fft_do with a constant on one channel """
     input    = new_fvec(buf_size, channels)
     fftgrain = new_cvec(buf_size, channels)
     # write impulse in channel 0, sample 0.
@@ -78,31 +77,37 @@
     some_constant = 0.003412432456
     for index in range(1,buf_size):
       fvec_write_sample(input, some_constant, 0, index)
-    aubio_mfft_do(self.o, input, fftgrain)
+    aubio_fft_do(self.o, input, fftgrain)
     # check norm and phase == 0 in all other channels 
     for index in range(buf_size/2+1):
       for channel in range(1, channels):
         self.assertEqual(0., cvec_read_norm(fftgrain, channel, index))
+        self.assertEqual(0., cvec_read_phas(fftgrain, channel, index))
+
     # check norm and phase == 0 in first first and last bin of first channel
-    self.assertAlmostEqual((buf_size-1)*some_constant, cvec_read_norm(fftgrain, 0, 0), precision)
-    self.assertEqual(0., cvec_read_phas(fftgrain, 0, 0))
-    self.assertEqual(0., cvec_read_norm(fftgrain, 0, buf_size/2+1))
-    self.assertEqual(0., cvec_read_phas(fftgrain, 0, buf_size/2+1))
-    # check unwrap2pi(phas) ~= pi everywhere but in first bin
+    # check unwrap2pi(phas) ~= pi everywhere but in first and last bin
+    self.assertCloseEnough(0., cvec_read_phas(fftgrain, 0, 0))
+    for index in range(1,buf_size/2):
+       self.assertCloseEnough(math.pi, aubio_unwrap2pi(cvec_read_phas(fftgrain, 0, index)))
+    self.assertCloseEnough(0., cvec_read_phas(fftgrain, 0, buf_size/2))
+    self.assertCloseEnough(0., cvec_read_phas(fftgrain, 0, buf_size/2+1))
+
+    self.assertCloseEnough((buf_size-1)*some_constant, cvec_read_norm(fftgrain, 0, 0))
     for index in range(1,buf_size/2+1):
-       self.assertAlmostEqual ( math.pi, aubio_unwrap2pi(cvec_read_phas(fftgrain, 0, index)), precision)
-       self.assertAlmostEqual(some_constant, cvec_read_norm(fftgrain, 0, index), precision)
+       self.assertCloseEnough(some_constant, abs(cvec_read_norm(fftgrain, 0, index)))
+    self.assertCloseEnough(0., cvec_read_norm(fftgrain, 0, buf_size/2+1))
+
     del fftgrain
     del input
 
-  def test_aubio_mfft_do_impulse_multichannel(self):
-    " test aubio_mfft_do on impulse two channels "
+  def test_do_impulse_multichannel(self):
+    " test aubio_fft_do on impulse two channels "
     input    = new_fvec(buf_size, channels)
     fftgrain = new_cvec(buf_size, channels)
     # put an impulse in first an last channel, at first and last index
     fvec_write_sample(input, 1., 0, 0)
     fvec_write_sample(input, 1., channels-1, 0)
-    aubio_mfft_do(self.o, input, fftgrain)
+    aubio_fft_do(self.o, input, fftgrain)
     # check the norm
     for index in range(buf_size/2+1):
       self.assertEqual(1., cvec_read_norm(fftgrain, 0, index))
@@ -118,21 +123,21 @@
     del fftgrain
     del input
 
-  def test_aubio_mfft_rdo_impulse(self):
-    """ test aubio_mfft_rdo on impulse """
+  def test_rdo_impulse(self):
+    """ test aubio_fft_rdo on impulse """
     fftgrain  = new_cvec(buf_size, channels)
     for channel in range(channels):
       cvec_write_norm(fftgrain, 1., channel, 0)
     output    = new_fvec(buf_size, channels)
-    aubio_mfft_rdo(self.o, fftgrain, output)
+    aubio_fft_rdo(self.o, fftgrain, output)
     for index in range(buf_size/2+1):
       for channel in range(channels):
-        self.assertAlmostEqual(fvec_read_sample(output, channel, index), 1./buf_size, precision)
+        self.assertCloseEnough(fvec_read_sample(output, channel, index), 1./buf_size)
     del fftgrain
     del output
 
-  def test_aubio_mfft_do_back_and_forth(self):
-    """ test aubio_mfft_rdo on a constant """
+  def test_do_back_and_forth(self):
+    """ test aubio_fft_rdo on a constant """
     input    = new_fvec(buf_size, channels)
     output   = new_fvec(buf_size, channels)
     fftgrain = new_cvec(buf_size, channels)
@@ -139,11 +144,11 @@
     for index in range(buf_size/2+1):
       for channel in range(channels):
         fvec_write_sample(input, 0.67, channel, index)
-    aubio_mfft_do(self.o, input, fftgrain)
-    aubio_mfft_rdo(self.o, fftgrain, output)
+    aubio_fft_do(self.o, input, fftgrain)
+    aubio_fft_rdo(self.o, fftgrain, output)
     for index in range(buf_size/2+1):
       for channel in range(channels):
-        self.assertAlmostEqual(fvec_read_sample(output, channel, index), 0.67, precision)
+        self.assertCloseEnough(0.67, fvec_read_sample(output, channel, index))
     del fftgrain
     del output
 
--- a/tests/python/phasevoc.py
+++ b/tests/python/phasevoc.py
@@ -8,7 +8,7 @@
 
 precision = 6
 
-class aubio_phasevoc_test(unittest.TestCase):
+class phasevoc_unit(unittest.TestCase):
 
   def setUp(self):
     self.o = new_aubio_pvoc(buf_size, hop_size, channels)
--- /dev/null
+++ b/tests/python/template.py
@@ -1,0 +1,18 @@
+
+import unittest
+
+class aubio_unit_template(unittest.TestCase):
+  
+  def assertCloseEnough(self, first, second, places=5, msg=None):
+        """Fail if the two objects are unequal as determined by their
+           *relative* difference rounded to the given number of decimal places
+           (default 7) and comparing to zero.
+        """
+        if round(first, places) == 0:
+          if round(second-first, places) != 0:
+              raise self.failureException, \
+                    (msg or '%r != %r within %r places' % (first, second, places))
+        else:
+          if round((second-first)/first, places) != 0:
+              raise self.failureException, \
+                    (msg or '%r != %r within %r places' % (first, second, places))