zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 7729d999239766f058c730418f4517db724a0cef
parent 5476e4e74b14a94e609a3af35ec7f447aaeb80a6
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sun, 14 Aug 2011 22:55:31 -0400

FFTW: R2C/C2R used over R2R interface

- Due to interleaving, this is marginally faster than old approach
- More importantly, it is easier to read

Diffstat:
Msrc/DSP/FFTwrapper.cpp | 105+++++++++++++++++++++----------------------------------------------------------
Msrc/DSP/FFTwrapper.h | 20++++++--------------
Msrc/Params/PADnoteParameters.cpp | 16++++++----------
Msrc/Synth/OscilGen.cpp | 8++++----
Msrc/globals.h | 7-------
5 files changed, 44 insertions(+), 112 deletions(-)

diff --git a/src/DSP/FFTwrapper.cpp b/src/DSP/FFTwrapper.cpp @@ -22,23 +22,22 @@ #include <cmath> #include <cassert> +#include <cstring> #include "FFTwrapper.h" FFTwrapper::FFTwrapper(int fftsize_) { - fftsize = fftsize_; - tmpfftdata1 = new fftw_real[fftsize]; - tmpfftdata2 = new fftw_real[fftsize]; - planfftw = fftw_plan_r2r_1d(fftsize, - tmpfftdata1, - tmpfftdata1, - FFTW_R2HC, - FFTW_ESTIMATE); - planfftw_inv = fftw_plan_r2r_1d(fftsize, - tmpfftdata2, - tmpfftdata2, - FFTW_HC2R, + fftsize = fftsize_; + time = new fftw_real[fftsize]; + fft = new fftw_complex[fftsize]; + planfftw = fftw_plan_dft_r2c_1d(fftsize, + time, + fft, FFTW_ESTIMATE); + planfftw_inv = fftw_plan_dft_c2r_1d(fftsize, + fft, + time, + FFTW_ESTIMATE); } FFTwrapper::~FFTwrapper() @@ -46,82 +45,34 @@ FFTwrapper::~FFTwrapper() fftw_destroy_plan(planfftw); fftw_destroy_plan(planfftw_inv); - delete [] tmpfftdata1; - delete [] tmpfftdata2; + delete [] time; + delete [] fft; } -/* - * do the Fast Fourier Transform - */ -void FFTwrapper::smps2freqs(const float *smps, FFTFREQS freqs) +void FFTwrapper::smps2freqs(const float *smps, fft_t *freqs) { - for(int i = 0; i < fftsize; i++) - tmpfftdata1[i] = smps[i]; - fftw_execute(planfftw); - for(int i = 0; i < fftsize / 2; i++) { - freqs.c[i] = tmpfftdata1[i]; - if(i != 0) - freqs.s[i] = tmpfftdata1[fftsize - i]; - } - tmpfftdata2[fftsize / 2] = 0.0; -} + //Load data + for(int i = 0; i < fftsize; ++i) + time[i] = static_cast<double>(smps[i]); -/* - * do the Inverse Fast Fourier Transform - */ -void FFTwrapper::freqs2smps(const FFTFREQS freqs, float *smps) -{ - tmpfftdata2[fftsize / 2] = 0.0; - for(int i = 0; i < fftsize / 2; i++) { - tmpfftdata2[i] = freqs.c[i]; - if(i != 0) - tmpfftdata2[fftsize - i] = freqs.s[i]; - } - fftw_execute(planfftw_inv); - for(int i = 0; i < fftsize; i++) - smps[i] = tmpfftdata2[i]; -} + //DFT + fftw_execute(planfftw); -//only OSCILLGEN SHOULD CALL THIS FOR NOW -void FFTwrapper::smps2freqs(const float *smps, fft_t *freqs) -{ - assert(fftsize==OSCIL_SIZE); - FFTFREQS tmp; - newFFTFREQS(&tmp, fftsize); - smps2freqs(smps, tmp); - for(int i = 0; i < fftsize / 2; ++i) - freqs[i] = fft_t(tmp.c[i], tmp.s[i]); - deleteFFTFREQS(&tmp); + //Grab data + memcpy((void*)freqs, (const void*)fft, fftsize*sizeof(double)); } void FFTwrapper::freqs2smps(const fft_t *freqs, float *smps) { - assert(fftsize==OSCIL_SIZE); - FFTFREQS tmp; - newFFTFREQS(&tmp, fftsize); - for(int i = 0; i < fftsize / 2; ++i) { - tmp.c[i] = freqs[i].real(); - tmp.s[i] = freqs[i].imag(); - } - freqs2smps(tmp, smps); - deleteFFTFREQS(&tmp); -} + //Load data + memcpy( (void*)fft, (const void*)freqs, fftsize*sizeof(double)); -void newFFTFREQS(FFTFREQS *f, int size) -{ - f->c = new float[size]; - f->s = new float[size]; - for(int i = 0; i < size; i++) { - f->c[i] = 0.0; - f->s[i] = 0.0; - } -} + //IDFT + fftw_execute(planfftw_inv); -void deleteFFTFREQS(FFTFREQS *f) -{ - delete[] f->c; - delete[] f->s; - f->c = f->s = NULL; + //Grab data + for(int i = 0; i < fftsize; ++i) + smps[i] = static_cast<float>(time[i]); } void FFT_cleanup() diff --git a/src/DSP/FFTwrapper.h b/src/DSP/FFTwrapper.h @@ -22,15 +22,10 @@ #ifndef FFT_WRAPPER_H #define FFT_WRAPPER_H - -#include "../globals.h" - #include <fftw3.h> -typedef double fftw_real; -typedef fftw_plan rfftw_plan; - #include <complex> -typedef std::complex<float> fft_t; +typedef double fftw_real; +typedef std::complex<fftw_real> fft_t; /**A wrapper for the FFTW library (Fast Fourier Transforms)*/ class FFTwrapper @@ -44,18 +39,15 @@ class FFTwrapper /**Convert Samples to Frequencies using Fourier Transform * @param smps Pointer to Samples to be converted; has length fftsize_ * @param freqs Structure FFTFREQS which stores the frequencies*/ - void smps2freqs(const float *smps, FFTFREQS freqs); - void freqs2smps(const FFTFREQS freqs, float *smps); void smps2freqs(const float *smps, fft_t *freqs); void freqs2smps(const fft_t *freqs, float *smps); private: - int fftsize; - fftw_real *tmpfftdata1, *tmpfftdata2; - rfftw_plan planfftw, planfftw_inv; + int fftsize; + fftw_real *time; + fftw_complex *fft; + fftw_plan planfftw, planfftw_inv; }; -void newFFTFREQS(FFTFREQS *f, int size); -void deleteFFTFREQS(FFTFREQS *f); void FFT_cleanup(); #endif diff --git a/src/Params/PADnoteParameters.cpp b/src/Params/PADnoteParameters.cpp @@ -469,7 +469,7 @@ void PADnoteParameters::generatespectrum_bandwidthMode(float *spectrum, float idfreq = i / (float)profilesize - 0.5; idfreq *= ibw; int spfreq = (int) (idfreq + ibasefreq); - float fspfreq = fmod(idfreq + ibasefreq, 1.0); + float fspfreq = fmod((double)idfreq + ibasefreq, 1.0); if(spfreq <= 0) continue; if(spfreq >= size - 1) @@ -577,9 +577,8 @@ void PADnoteParameters::applyparameters(bool lockmutex) samplemax = 1; //prepare a BIG FFT stuff - FFTwrapper *fft = new FFTwrapper(samplesize); - FFTFREQS fftfreqs; - newFFTFREQS(&fftfreqs, samplesize / 2); + FFTwrapper *fft = new FFTwrapper(samplesize); + fft_t *fftfreqs = new fft_t[samplesize / 2]; float adj[samplemax]; //this is used to compute frequency relation to the base frequency for(int nsample = 0; nsample < samplemax; nsample++) @@ -603,11 +602,8 @@ void PADnoteParameters::applyparameters(bool lockmutex) newsample.smp = new float[samplesize + extra_samples]; newsample.smp[0] = 0.0; - for(int i = 1; i < spectrumsize; i++) { //randomize the phases - float phase = RND * 6.29; - fftfreqs.c[i] = spectrum[i] * cos(phase); - fftfreqs.s[i] = spectrum[i] * sin(phase); - } + for(int i = 1; i < spectrumsize; i++) //randomize the phases + fftfreqs[i] = std::polar(spectrum[i], (float)RND * 6.29f); fft->freqs2smps(fftfreqs, newsample.smp); //that's all; here is the only ifft for the whole sample; no windows are used ;-) @@ -644,7 +640,7 @@ void PADnoteParameters::applyparameters(bool lockmutex) newsample.smp = NULL; } delete (fft); - deleteFFTFREQS(&fftfreqs); + delete[] fftfreqs; //delete the additional samples that might exists and are not useful if(lockmutex) { diff --git a/src/Synth/OscilGen.cpp b/src/Synth/OscilGen.cpp @@ -525,7 +525,7 @@ void OscilGen::spectrumadjust() mag = 1.0; break; } - oscilFFTfreqs[i] = std::polar(mag, phase); + oscilFFTfreqs[i] = std::polar<fftw_real>(mag, phase); } } @@ -623,7 +623,7 @@ void OscilGen::prepare() int k = i * (j + 1); if(k >= OSCIL_SIZE / 2) break; - oscilFFTfreqs[k] += basefuncFFTfreqs[i] * std::polar(hmag[j], hphase[j] * k); + oscilFFTfreqs[k] += basefuncFFTfreqs[i] * std::polar<fftw_real>(hmag[j], hphase[j] * k); } } } @@ -727,7 +727,7 @@ void OscilGen::adaptiveharmonicpostprocess(fft_t *f, int size) par = 1.0 - pow((1.0 - par), 1.5); for(int i = 0; i < size; i++) { - inf[i] = f[i] * par; + inf[i] = f[i] * double(par); f[i] *= (1.0 - par); } @@ -846,7 +846,7 @@ short int OscilGen::get(float *smps, float freqHz, int resonance) if((Prand > 64) && (freqHz >= 0.0) && (!ADvsPAD)) { const float rnd = PI * pow((Prand - 64.0) / 64.0, 2.0); for(int i = 1; i < nyquist - 1; i++) //to Nyquist only for AntiAliasing - outoscilFFTfreqs[i] *= std::polar(1.0f, (float)(rnd * i * RND)); + outoscilFFTfreqs[i] *= std::polar<fftw_real>(1.0f, (float)(rnd * i * RND)); } //Harmonic Amplitude Randomness diff --git a/src/globals.h b/src/globals.h @@ -25,13 +25,6 @@ #ifndef GLOBALS_H #define GLOBALS_H -struct FFTFREQS { - float *s, *c; //sine and cosine components -}; - -extern void newFFTFREQS(FFTFREQS *f, int size); -extern void deleteFFTFREQS(FFTFREQS *f); - /**Sampling rate*/ extern int SAMPLE_RATE;