Mercurial > hg > devuvuzelator
changeset 9:a1539d4e3b08
* Tidy code, start doc
author | Chris Cannam |
---|---|
date | Sat, 12 Jun 2010 13:08:33 +0100 |
parents | e15ebd222c63 |
children | 25580443645c |
files | Makefile devuvuzelator-ladspa.cpp devuvuzelator-ladspa.h devuvuzelator-vst.cpp devuvuzelator-vst.h devuvuzelator.cpp fft.cpp median.h params.h |
diffstat | 9 files changed, 377 insertions(+), 479 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Sat Jun 12 13:08:33 2010 +0100 @@ -0,0 +1,17 @@ + +CXXFLAGS := -DLADSPA -fpic -O3 -ffast-math -msse -msse2 -mfpmath=sse -ftree-vectorize + +SOURCES := devuvuzelator.cpp devuvuzelator-ladspa.cpp fft.cpp +OBJECTS := devuvuzelator.o devuvuzelator-ladspa.o fft.o +HEADERS := devuvuzelator-ladspa.h params.h median.h + +devuvuzelator.so: $(SOURCES) + $(CXX) $^ $(CXXFLAGS) -shared -o $@ + +clean: + rm -f $(OBJECTS) + +devuvuzelator.cpp: $(HEADERS) +devuvuzelator-ladspa.cpp: $(HEADERS) +fft.cpp: $(HEADERS) +
--- a/devuvuzelator-ladspa.cpp Fri Jun 11 20:20:20 2010 +0100 +++ b/devuvuzelator-ladspa.cpp Sat Jun 12 13:08:33 2010 +0100 @@ -1,85 +1,12 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -#include <ladspa.h> +#include "devuvuzelator-ladspa.h" + #include <alloca.h> #include <iostream> #include <cmath> -#include "median.h" - -#define FFTSIZE 4096 -#define WINSIZE 1024 - -class Devuvuzelator -{ -public: - static const LADSPA_Descriptor *getDescriptor(unsigned long index); - -private: - Devuvuzelator(int sampleRate); - ~Devuvuzelator(); - - enum { - InputPort = 0, - OutputPort = 1, - LatencyPort = 2, - FundamentalPort = 3, - BandwidthPort = 4, - HarmonicsPort = 5, - ReductionPort = 6, - PortCount = 7, - }; - - static const char *const portNames[PortCount]; - static const LADSPA_PortDescriptor ports[PortCount]; - static const LADSPA_PortRangeHint hints[PortCount]; - static const LADSPA_Properties properties; - static const LADSPA_Descriptor ladspaDescriptor; - - static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long); - static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *); - static void activate(LADSPA_Handle); - static void run(LADSPA_Handle, unsigned long); - static void deactivate(LADSPA_Handle); - static void cleanup(LADSPA_Handle); - - void reset(); - void window(float *); - void runImpl(unsigned long); - void processFrame(); - void processSpectralFrame(); - void updateParameters(); - - static void fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io); - - int m_sampleRate; - float *m_input; - float *m_output; - - float m_fundamental; - float m_bandwidth; - float m_harmonics; - float m_reduction; - - float *m_platency; - float *m_pfundamental; - float *m_pbandwidth; - float *m_pharmonics; - float *m_preduction; - - const int m_fftsize; - const int m_winsize; - const int m_increment; - int m_fill; - int m_read; - float *m_buffer; - float *m_outacc; - double *m_real; - double *m_imag; - double *m_window; - MedianFilter<double> **m_medians; -}; +#include "params.h" const char *const Devuvuzelator::portNames[PortCount] = @@ -167,6 +94,7 @@ m_fftsize(FFTSIZE), m_winsize(WINSIZE), m_increment(m_winsize/2), + m_filtersecs(FILTERSECS), m_fill(0), m_read(0) { @@ -358,130 +286,9 @@ } } -// FFT implementation by Don Cross, public domain. -// This version scales the forward transform. - -void Devuvuzelator::fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io) -{ - if (!ri || !ro || !io) return; - - unsigned int bits; - unsigned int i, j, k, m; - unsigned int blockSize, blockEnd; - - double tr, ti; - - if (n < 2) return; - if (n & (n-1)) return; - - double angle = 2.0 * M_PI; - if (inverse) angle = -angle; - - for (i = 0; ; ++i) { - if (n & (1 << i)) { - bits = i; - break; - } - } - - static unsigned int tableSize = 0; - static int *table = 0; - - if (tableSize != n) { - - delete[] table; - - table = new int[n]; - - for (i = 0; i < n; ++i) { - - m = i; - - for (j = k = 0; j < bits; ++j) { - k = (k << 1) | (m & 1); - m >>= 1; - } - - table[i] = k; - } - - tableSize = n; - } - - if (ii) { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = ii[i]; - } - } else { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = 0.0; - } - } - - blockEnd = 1; - - for (blockSize = 2; blockSize <= n; blockSize <<= 1) { - - double delta = angle / (double)blockSize; - double sm2 = -sin(-2 * delta); - double sm1 = -sin(-delta); - double cm2 = cos(-2 * delta); - double cm1 = cos(-delta); - double w = 2 * cm1; - double ar[3], ai[3]; - - for (i = 0; i < n; i += blockSize) { - - ar[2] = cm2; - ar[1] = cm1; - - ai[2] = sm2; - ai[1] = sm1; - - for (j = i, m = 0; m < blockEnd; j++, m++) { - - ar[0] = w * ar[1] - ar[2]; - ar[2] = ar[1]; - ar[1] = ar[0]; - - ai[0] = w * ai[1] - ai[2]; - ai[2] = ai[1]; - ai[1] = ai[0]; - - k = j + blockEnd; - tr = ar[0] * ro[k] - ai[0] * io[k]; - ti = ar[0] * io[k] + ai[0] * ro[k]; - - ro[k] = ro[j] - tr; - io[k] = io[j] - ti; - - ro[j] += tr; - io[j] += ti; - } - } - - blockEnd = blockSize; - } - - if (!inverse) { - - double denom = (double)n; - - for (i = 0; i < n; i++) { - ro[i] /= denom; - io[i] /= denom; - } - } -} - const LADSPA_Descriptor * ladspa_descriptor(unsigned long ix) { return Devuvuzelator::getDescriptor(ix); } -#include "devuvuzelator.cpp" -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devuvuzelator-ladspa.h Sat Jun 12 13:08:33 2010 +0100 @@ -0,0 +1,82 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#ifndef _DEVUVUZELATOR_LADSPA_H_ +#define _DEVUVUZELATOR_LADSPA_H_ + +#include <ladspa.h> + +#include "median.h" + +class Devuvuzelator +{ +public: + static const LADSPA_Descriptor *getDescriptor(unsigned long index); + +private: + Devuvuzelator(int sampleRate); + ~Devuvuzelator(); + + enum { + InputPort = 0, + OutputPort = 1, + LatencyPort = 2, + FundamentalPort = 3, + BandwidthPort = 4, + HarmonicsPort = 5, + ReductionPort = 6, + PortCount = 7, + }; + + static const char *const portNames[PortCount]; + static const LADSPA_PortDescriptor ports[PortCount]; + static const LADSPA_PortRangeHint hints[PortCount]; + static const LADSPA_Properties properties; + static const LADSPA_Descriptor ladspaDescriptor; + + static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long); + static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *); + static void activate(LADSPA_Handle); + static void run(LADSPA_Handle, unsigned long); + static void deactivate(LADSPA_Handle); + static void cleanup(LADSPA_Handle); + + void reset(); + void window(float *); + void runImpl(unsigned long); + void processFrame(); + void processSpectralFrame(); + void updateParameters(); + + static void fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io); + + int m_sampleRate; + float *m_input; + float *m_output; + + float m_fundamental; + float m_bandwidth; + float m_harmonics; + float m_reduction; + + float *m_platency; + float *m_pfundamental; + float *m_pbandwidth; + float *m_pharmonics; + float *m_preduction; + + const int m_fftsize; + const int m_winsize; + const int m_increment; + const float m_filtersecs; + int m_fill; + int m_read; + float *m_buffer; + float *m_outacc; + double *m_real; + double *m_imag; + double *m_window; + MedianFilter<double> **m_medians; +}; + +#endif
--- a/devuvuzelator-vst.cpp Fri Jun 11 20:20:20 2010 +0100 +++ b/devuvuzelator-vst.cpp Sat Jun 12 13:08:33 2010 +0100 @@ -1,95 +1,17 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +#include "devuvuzelator-vst.h" + #define _USE_MATH_DEFINES - +#include <cmath> #include <iostream> -#include <cmath> #include <cstdio> -#include "public.sdk/source/vst2.x/audioeffect.h" +#include "params.h" #define snprintf _snprintf #define alloca _alloca -#define FFTSIZE 1024 -#define WINSIZE 1024 - -#include "median.h" - -class Devuvuzelator : public AudioEffect -{ - enum { - FundamentalParam = 0, - BandwidthParam = 1, - HarmonicsParam = 2, - ReductionParam = 3, - NumParams = 4 - }; - -public: - Devuvuzelator(audioMasterCallback cb); - ~Devuvuzelator(); - - virtual void getEffectName(char *n) { - vst_strncpy(n, "Devuvuzelator", kVstMaxEffectNameLen); - } - virtual void getProductString(char *n) { - vst_strncpy(n, "Devuvuzelator", kVstMaxProductStrLen); - } - virtual void getVendorString(char *n) { - vst_strncpy(n, "Queen Mary, University of London", kVstMaxVendorStrLen); - } - - virtual void setParameter(VstInt32 index, float value); - virtual float getParameter(VstInt32 index); - virtual void getParameterLabel(VstInt32 index, char* label); - virtual void getParameterDisplay(VstInt32 index, char* text); - virtual void getParameterName(VstInt32 index, char* text); - - virtual void setSampleRate (float sampleRate) { - m_sampleRate = sampleRate; - AudioEffect::setSampleRate(sampleRate); - } - - virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) { - m_input = inputs[0]; - m_output = outputs[0]; - runImpl(sampleFrames); - } - - void reset(); - void window(float *); - void runImpl(unsigned long); - void processFrame(); - void processSpectralFrame(); - - static void fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io); - - float m_sampleRate; - float *m_input; - float *m_output; - - float m_fundamental; - float m_bandwidth; - int m_harmonics; - float m_reduction; - - const int m_fftsize; - const int m_winsize; - const int m_increment; - int m_fill; - int m_read; - float *m_buffer; - float *m_outacc; - double *m_frame; - double *m_spare; - double *m_real; - double *m_imag; - double *m_window; - MedianFilter<double> **m_medians; -}; - // VST params 0->1 void @@ -164,14 +86,15 @@ m_fftsize(FFTSIZE), m_winsize(WINSIZE), m_increment(m_winsize/2), + m_filtersecs(FILTERSECS), m_fill(0), m_read(0) { m_buffer = new float[m_winsize]; m_outacc = new float[m_winsize * 2]; m_window = new double[m_winsize]; - m_frame = new double[m_fftsize]; - m_spare = new double[m_fftsize]; + m_frame = new double[m_fftsize]; + m_spare = new double[m_fftsize]; m_real = new double[m_fftsize]; m_imag = new double[m_fftsize]; m_medians = new MedianFilter<double> *[m_fftsize/2+1]; @@ -201,8 +124,8 @@ { delete[] m_buffer; delete[] m_outacc; - delete[] m_frame; - delete[] m_spare; + delete[] m_frame; + delete[] m_spare; delete[] m_real; delete[] m_imag; delete[] m_window; @@ -234,51 +157,19 @@ if (!m_input || !m_output) return; const int sc = sampleCount; -/* - static FILE *blah = 0; - if (!blah) { - blah = fopen("d:\\devuvu-counts.txt", "w"); - } - if (m_input == m_output) fprintf(blah, "in-place\n"); -*/ - float *output = m_output; - if (m_input == m_output) { - output = (float *)alloca(sampleCount * sizeof(float)); - } -/* - float inmean = 0; - for (int i = 0; i < sc; ++i) { - inmean += m_input[i] * m_input[i]; - fprintf(blah, "i:%d:%f ", i, m_input[i]); - } - inmean/=sc; - inmean = sqrt(inmean); + float *output = m_output; + if (m_input == m_output) { + output = (float *)alloca(sampleCount * sizeof(float)); + } - fprintf(blah, "%d\n", (int)sampleCount); - fflush(blah); -*/ - int oi = 0; - for (int ii = 0; ii < sc; ++ii) { + int oi = 0; + for (int ii = 0; ii < sc; ++ii) { - output[oi++] = m_outacc[m_read++]; -// m_output[oi++] = inmean * float(ii%100)/100; -// m_read++; + output[oi++] = m_outacc[m_read++]; if (m_fill == m_winsize) { processFrame(); -/* - for (int i = 0; i < m_winsize; ++i) { - float v = m_buffer[i]; - fprintf(blah, "%f ", v); - m_outacc[m_winsize + i] = m_buffer[i];//m_input[i];//m_buffer[i] ;//* m_window[i]; - } - fprintf(blah, "\n"); - -// for (int j = 0; j < m_winsize; ++j) { -// m_outacc[m_winsize+j] = inmean * float(j%100)/100; -// } -*/ for (int j = m_increment; j < m_winsize; ++j) { m_buffer[j - m_increment] = m_buffer[j]; @@ -295,34 +186,18 @@ m_fill = m_fill - m_increment; m_read = m_read - m_increment; } -/* - fprintf(blah, "%d:%f ", ii, m_input[ii]); -*/ - m_buffer[m_fill] = m_input[ii]; - ++m_fill; + m_buffer[m_fill] = m_input[ii]; + ++m_fill; } - static int block = 0; - for (int i = 0; i < sc; ++i) { -// m_output[i] = float(block % 100) / 100; -// m_output[i] = inmean * float(i % 100) / 100; - } - ++block; - - if (m_input == m_output) { - for (int i = 0; i < sc; ++i) m_output[i] = output[i]; - } + if (m_input == m_output) { + for (int i = 0; i < sc; ++i) m_output[i] = output[i]; + } } void Devuvuzelator::processFrame() { -/* for (int i = 0; i < m_winsize; ++i) { - m_outacc[m_winsize + i] += m_buffer[i] ;//* m_window[i]; - } - return; -*/ - for (int i = 0; i < m_fftsize; ++i) { m_frame[i] = 0.0; } @@ -336,7 +211,7 @@ fft(m_fftsize, false, m_frame, 0, m_real, m_imag); -// processSpectralFrame(); + processSpectralFrame(); for (int i = 0; i < m_fftsize/2-1; ++i) { m_real[m_fftsize-i-1] = m_real[i+1]; @@ -353,129 +228,9 @@ } } -// FFT implementation by Don Cross, public domain. -// This version scales the forward transform. - -void Devuvuzelator::fft(unsigned int n, bool inverse, - double *ri, double *ii, double *ro, double *io) -{ - if (!ri || !ro || !io) return; - - unsigned int bits; - unsigned int i, j, k, m; - unsigned int blockSize, blockEnd; - - double tr, ti; - - if (n < 2) return; - if (n & (n-1)) return; - - double angle = 2.0 * M_PI; - if (inverse) angle = -angle; - - for (i = 0; ; ++i) { - if (n & (1 << i)) { - bits = i; - break; - } - } - - static unsigned int tableSize = 0; - static int *table = 0; - - if (tableSize != n) { - - delete[] table; - - table = new int[n]; - - for (i = 0; i < n; ++i) { - - m = i; - - for (j = k = 0; j < bits; ++j) { - k = (k << 1) | (m & 1); - m >>= 1; - } - - table[i] = k; - } - - tableSize = n; - } - - if (ii) { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = ii[i]; - } - } else { - for (i = 0; i < n; ++i) { - ro[table[i]] = ri[i]; - io[table[i]] = 0.0; - } - } - - blockEnd = 1; - - for (blockSize = 2; blockSize <= n; blockSize <<= 1) { - - double delta = angle / (double)blockSize; - double sm2 = -sin(-2 * delta); - double sm1 = -sin(-delta); - double cm2 = cos(-2 * delta); - double cm1 = cos(-delta); - double w = 2 * cm1; - double ar[3], ai[3]; - - for (i = 0; i < n; i += blockSize) { - - ar[2] = cm2; - ar[1] = cm1; - - ai[2] = sm2; - ai[1] = sm1; - - for (j = i, m = 0; m < blockEnd; j++, m++) { - - ar[0] = w * ar[1] - ar[2]; - ar[2] = ar[1]; - ar[1] = ar[0]; - - ai[0] = w * ai[1] - ai[2]; - ai[2] = ai[1]; - ai[1] = ai[0]; - - k = j + blockEnd; - tr = ar[0] * ro[k] - ai[0] * io[k]; - ti = ar[0] * io[k] + ai[0] * ro[k]; - - ro[k] = ro[j] - tr; - io[k] = io[j] - ti; - - ro[j] += tr; - io[j] += ti; - } - } - - blockEnd = blockSize; - } - - if (!inverse) { - - double denom = (double)n; - - for (i = 0; i < n; i++) { - ro[i] /= denom; - io[i] /= denom; - } - } -} - AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new Devuvuzelator(audioMaster); } -#include "devuvuzelator.cpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devuvuzelator-vst.h Sat Jun 12 13:08:33 2010 +0100 @@ -0,0 +1,84 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#ifndef _DEVUVUZELATOR_VST_H_ +#define _DEVUVUZELATOR_VST_H_ + +#include "public.sdk/source/vst2.x/audioeffect.h" +#include "median.h" + +class Devuvuzelator : public AudioEffect +{ + enum { + FundamentalParam = 0, + BandwidthParam = 1, + HarmonicsParam = 2, + ReductionParam = 3, + NumParams = 4 + }; + +public: + Devuvuzelator(audioMasterCallback cb); + ~Devuvuzelator(); + + virtual void getEffectName(char *n) { + vst_strncpy(n, "Devuvuzelator", kVstMaxEffectNameLen); + } + virtual void getProductString(char *n) { + vst_strncpy(n, "Devuvuzelator", kVstMaxProductStrLen); + } + virtual void getVendorString(char *n) { + vst_strncpy(n, "Queen Mary, University of London", kVstMaxVendorStrLen); + } + + virtual void setParameter(VstInt32 index, float value); + virtual float getParameter(VstInt32 index); + virtual void getParameterLabel(VstInt32 index, char* label); + virtual void getParameterDisplay(VstInt32 index, char* text); + virtual void getParameterName(VstInt32 index, char* text); + + virtual void setSampleRate (float sampleRate) { + m_sampleRate = sampleRate; + AudioEffect::setSampleRate(sampleRate); + } + + virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) { + m_input = inputs[0]; + m_output = outputs[0]; + runImpl(sampleFrames); + } + + void reset(); + void window(float *); + void runImpl(unsigned long); + void processFrame(); + void processSpectralFrame(); + + static void fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io); + + float m_sampleRate; + float *m_input; + float *m_output; + + float m_fundamental; + float m_bandwidth; + int m_harmonics; + float m_reduction; + + const int m_fftsize; + const int m_winsize; + const int m_increment; + const float m_filtersecs; + int m_fill; + int m_read; + float *m_buffer; + float *m_outacc; + double *m_frame; + double *m_spare; + double *m_real; + double *m_imag; + double *m_window; + MedianFilter<double> **m_medians; +}; + +#endif
--- a/devuvuzelator.cpp Fri Jun 11 20:20:20 2010 +0100 +++ b/devuvuzelator.cpp Sat Jun 12 13:08:33 2010 +0100 @@ -1,19 +1,29 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ +#ifdef VST +#include "devuvuzelator-vst.h" +#else +#ifdef LADSPA +#include "devuvuzelator-ladspa.h" +#else +#error Need to define either VST or LADSPA +#endif +#endif + void Devuvuzelator::processSpectralFrame() { const int hs = m_fftsize/2 + 1; double *mags = (double *)alloca(hs * sizeof(double)); - double *ratios = (double *)alloca(hs * sizeof(double)); for (int i = 0; i < hs; ++i) { - ratios[i] = 1.0; mags[i] = sqrt(m_real[i] * m_real[i] + m_imag[i] * m_imag[i]); } double lowfun = m_fundamental - m_bandwidth/2; double highfun = m_fundamental + m_bandwidth/2; + int ix = 0; + for (int h = 1; h <= m_harmonics; ++h) { double lowfreq = lowfun * h; @@ -23,30 +33,31 @@ int highbin = 0.5 + (m_fftsize * highfreq) / m_sampleRate; for (int i = lowbin; i <= highbin; ++i) { -/* + if (!m_medians[i]) { - const float filtersecs = 5.f; - int filterlen = (filtersecs * m_sampleRate) / m_increment; + // allocation in RT context, sorry! but this happens only + // the first time through + int filterlen = (m_filtersecs * m_sampleRate) / m_increment; m_medians[i] = new MedianFilter<double>(filterlen); } m_medians[i]->push(mags[i]); double threshold = m_medians[i]->getAt(m_reduction); - */ - double threshold = 0.0; - if (mags[i] > threshold && mags[i] > 0.0) { + if (ix++ == 2) { + std::cerr << "threshold = " << threshold << std::endl; + } + + if (mags[i] > threshold && mags[i] > 0.0) { double target = mags[i] - threshold; - ratios[i] = (target / mags[i]); + double ratio = (target / mags[i]); + m_real[i] *= ratio; + m_imag[i] *= ratio; } else { - ratios[i] = 0.0; + m_real[i] = 0.0; + m_imag[i] = 0.0; } } } - - for (int i = 0; i < hs; ++i) { - m_real[i] *= ratios[i]; - m_imag[i] *= ratios[i]; - } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fft.cpp Sat Jun 12 13:08:33 2010 +0100 @@ -0,0 +1,131 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#ifdef VST +#include "devuvuzelator-vst.h" +#else +#ifdef LADSPA +#include "devuvuzelator-ladspa.h" +#else +#error Need to define either VST or LADSPA +#endif +#endif + +// FFT implementation by Don Cross, public domain. +// This version scales the forward transform. + +void Devuvuzelator::fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io) +{ + if (!ri || !ro || !io) return; + + unsigned int bits; + unsigned int i, j, k, m; + unsigned int blockSize, blockEnd; + + double tr, ti; + + if (n < 2) return; + if (n & (n-1)) return; + + double angle = 2.0 * M_PI; + if (inverse) angle = -angle; + + for (i = 0; ; ++i) { + if (n & (1 << i)) { + bits = i; + break; + } + } + + static unsigned int tableSize = 0; + static int *table = 0; + + if (tableSize != n) { + + delete[] table; + + table = new int[n]; + + for (i = 0; i < n; ++i) { + + m = i; + + for (j = k = 0; j < bits; ++j) { + k = (k << 1) | (m & 1); + m >>= 1; + } + + table[i] = k; + } + + tableSize = n; + } + + if (ii) { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = ii[i]; + } + } else { + for (i = 0; i < n; ++i) { + ro[table[i]] = ri[i]; + io[table[i]] = 0.0; + } + } + + blockEnd = 1; + + for (blockSize = 2; blockSize <= n; blockSize <<= 1) { + + double delta = angle / (double)blockSize; + double sm2 = -sin(-2 * delta); + double sm1 = -sin(-delta); + double cm2 = cos(-2 * delta); + double cm1 = cos(-delta); + double w = 2 * cm1; + double ar[3], ai[3]; + + for (i = 0; i < n; i += blockSize) { + + ar[2] = cm2; + ar[1] = cm1; + + ai[2] = sm2; + ai[1] = sm1; + + for (j = i, m = 0; m < blockEnd; j++, m++) { + + ar[0] = w * ar[1] - ar[2]; + ar[2] = ar[1]; + ar[1] = ar[0]; + + ai[0] = w * ai[1] - ai[2]; + ai[2] = ai[1]; + ai[1] = ai[0]; + + k = j + blockEnd; + tr = ar[0] * ro[k] - ai[0] * io[k]; + ti = ar[0] * io[k] + ai[0] * ro[k]; + + ro[k] = ro[j] - tr; + io[k] = io[j] - ti; + + ro[j] += tr; + io[j] += ti; + } + } + + blockEnd = blockSize; + } + + if (!inverse) { + + double denom = (double)n; + + for (i = 0; i < n; i++) { + ro[i] /= denom; + io[i] /= denom; + } + } +} +