# HG changeset patch # User Chris Cannam # Date 1276248689 -3600 # Node ID 0d2126c323093aa377ee7936d5ff4d80804702c1 # Parent fe4c331213c5fdd96e9e57d8e4556079292ec3c3 * split out core code, fix some things diff -r fe4c331213c5 -r 0d2126c32309 devuvuzelator-ladspa.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devuvuzelator-ladspa.cpp Fri Jun 11 10:31:29 2010 +0100 @@ -0,0 +1,444 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#include +#include +#include +#include + +#define FFTSIZE 1024 + +class Devuvuzelator +{ +public: + static const LADSPA_Descriptor *getDescriptor(unsigned long index); + +private: + Devuvuzelator(int sampleRate); + ~Devuvuzelator(); + + enum { + InputPort = 0, + OutputPort = 1, + LowPort = 2, + HighPort = 3, + FundamentalPort = 4, + BandwidthPort = 5, + HarmonicsPort = 6, + ReductionPort = 7, + PortCount = 8, + }; + + 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(); + + 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_low; + float *m_high; + float *m_fundamental; + float *m_bandwidth; + float *m_harmonics; + float *m_reduction; + + const int m_fftsize; + 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; +}; + +const char *const +Devuvuzelator::portNames[PortCount] = +{ + "Input", + "Output", + "Low threshold (dB)", + "High threshold (dB)", + "Fundamental frequency (Hz)", + "Bandwidth of fundamental (Hz)", + "Number of partials", + "Reduction (dB)", +}; + +const LADSPA_PortDescriptor +Devuvuzelator::ports[PortCount] = +{ + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, +}; + +const LADSPA_PortRangeHint +Devuvuzelator::hints[PortCount] = +{ + { 0, 0, 0 }, + { 0, 0, 0 }, + { LADSPA_HINT_DEFAULT_MIDDLE | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, -80, 0 }, + { LADSPA_HINT_DEFAULT_HIGH | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, -80, 0 }, + { LADSPA_HINT_DEFAULT_LOW | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 110, 550 }, + { LADSPA_HINT_DEFAULT_MIDDLE | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 20, 100 }, + { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 6 }, + { LADSPA_HINT_DEFAULT_MIDDLE | + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 20 }, +}; + +const LADSPA_Properties +Devuvuzelator::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + +const LADSPA_Descriptor +Devuvuzelator::ladspaDescriptor = +{ + 0, // "Unique" ID + "devuvuzelator", // Label + properties, + "Devuvuzelator", // Name + "Queen Mary, University of London", // Maker + "All Rights Reserved", // Copyright + PortCount, + ports, + portNames, + hints, + 0, // Implementation data + instantiate, + connectPort, + activate, + run, + 0, // Run adding + 0, // Set run adding gain + deactivate, + cleanup +}; + +const LADSPA_Descriptor * +Devuvuzelator::getDescriptor(unsigned long index) +{ + if (index == 0) return &ladspaDescriptor; + return 0; +} + +Devuvuzelator::Devuvuzelator(int sampleRate) : + m_sampleRate(sampleRate), + m_input(0), + m_output(0), + m_low(0), + m_high(0), + m_fftsize(FFTSIZE), + m_increment(m_fftsize/4), + m_fill(0), + m_read(0) +{ + m_buffer = new float[m_fftsize]; + m_outacc = new float[m_fftsize * 2]; + m_real = new double[m_fftsize]; + m_imag = new double[m_fftsize]; + m_window = new double[m_fftsize]; + + for (int i = 0; i < m_fftsize; ++i) { + m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_fftsize); + } + + reset(); +} + +Devuvuzelator::~Devuvuzelator() +{ + delete[] m_buffer; + delete[] m_outacc; + delete[] m_real; + delete[] m_imag; + delete[] m_window; +} + +LADSPA_Handle +Devuvuzelator::instantiate(const LADSPA_Descriptor *, unsigned long rate) +{ + Devuvuzelator *devuvu = new Devuvuzelator(rate); + return devuvu; +} + +void +Devuvuzelator::connectPort(LADSPA_Handle handle, + unsigned long port, LADSPA_Data *location) +{ + Devuvuzelator *devuvu = (Devuvuzelator *)handle; + + float **ports[PortCount] = { + &devuvu->m_input, + &devuvu->m_output, + &devuvu->m_low, + &devuvu->m_high, + &devuvu->m_fundamental, + &devuvu->m_bandwidth, + &devuvu->m_harmonics, + &devuvu->m_reduction, + }; + + *ports[port] = (float *)location; +} + +void +Devuvuzelator::activate(LADSPA_Handle handle) +{ + Devuvuzelator *devuvu = (Devuvuzelator *)handle; + devuvu->reset(); +} + +void +Devuvuzelator::run(LADSPA_Handle handle, unsigned long samples) +{ + Devuvuzelator *devuvu = (Devuvuzelator *)handle; + devuvu->runImpl(samples); +} + +void +Devuvuzelator::deactivate(LADSPA_Handle handle) +{ + activate(handle); // both functions just reset the plugin +} + +void +Devuvuzelator::cleanup(LADSPA_Handle handle) +{ + delete (Devuvuzelator *)handle; +} + +void +Devuvuzelator::reset() +{ + for (int i = 0; i < m_fftsize; ++i) { + m_buffer[i] = 0.f; + } + for (int i = 0; i < m_fftsize*2; ++i) { + m_outacc[i] = 0.f; + } + m_fill = 0; + m_read = 0; +} + +void +Devuvuzelator::runImpl(unsigned long sampleCount) +{ + if (!m_input || !m_output) return; + + int ii = 0; + int oi = 0; + const int sc = sampleCount; + + while (ii < sc) { + + m_output[oi++] = m_outacc[m_read++] / 1.5f; + + if (m_fill == m_fftsize) { + + processFrame(); + + for (int j = m_increment; j < m_fftsize; ++j) { + m_buffer[j - m_increment] = m_buffer[j]; + } + + for (int j = m_increment; j < m_fftsize*2; ++j) { + m_outacc[j - m_increment] = m_outacc[j]; + } + + for (int j = m_fftsize*2 - m_increment; j < m_fftsize*2; ++j) { + m_outacc[j] = 0.f; + } + + m_fill -= m_increment; + m_read -= m_increment; + } + + m_buffer[m_fill++] = m_input[ii++]; + } +} + +void +Devuvuzelator::processFrame() +{ + double *frame = (double *)alloca(m_fftsize * sizeof(double)); + int ix = m_fftsize/2; + for (int i = 0; i < m_fftsize; ++i) { + frame[ix++] = m_buffer[i] * m_window[i]; + if (ix == m_fftsize) ix = 0; + } + + fft(m_fftsize, false, frame, 0, m_real, m_imag); + + processSpectralFrame(); + + for (int i = 0; i < m_fftsize/2-1; ++i) { + m_real[m_fftsize-i] = m_real[i+1]; + m_imag[m_fftsize-i] = -m_imag[i+1]; + } + + double *spare = (double *)alloca(m_fftsize * sizeof(double)); + fft(m_fftsize, true, m_real, m_imag, frame, spare); + + ix = m_fftsize/2; + for (int i = 0; i < m_fftsize; ++i) { + m_outacc[m_fftsize + i] += frame[ix++] * m_window[i]; + if (ix == m_fftsize) ix = 0; + } +} + +// 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" + diff -r fe4c331213c5 -r 0d2126c32309 devuvuzelator-vst.cpp --- a/devuvuzelator-vst.cpp Thu Jun 10 21:39:32 2010 +0100 +++ b/devuvuzelator-vst.cpp Fri Jun 11 10:31:29 2010 +0100 @@ -64,8 +64,8 @@ float *m_input; float *m_output; + float m_low; float m_high; - float m_low; float m_fundamental; float m_bandwidth; float m_harmonics; @@ -82,34 +82,32 @@ double *m_window; }; +// VST params 0->1 + void Devuvuzelator::setParameter(VstInt32 index, float value) { - float *params[NumParams] = { - m_low, - m_high, - m_fundamental, - m_bandwidth, - m_harmonics, - m_reduction, - }; - - *params[index] = value; + switch (index) { + case 0: m_low = -80 + 80 * value; break; + case 1: m_high = -80 + 80 * value; break; + case 2: m_fundamental = 110 + 440 * value; break; + case 3: m_bandwidth = 20 + 80 * value; break; + case 4: m_harmonics = int(value * 6 + 0.5); break; + case 5: m_reduction = 20 * value; break; + } } float Devuvuzelator::getParameter(VstInt32 index) { - float *params[NumParams] = { - m_low, - m_high, - m_fundamental, - m_bandwidth, - m_harmonics, - m_reduction, - }; - - return *params[index]; + switch (index) { + case 0: return (m_low + 80) / 80; + case 1: return (m_high + 80) / 80; + case 2: return (m_fundamental - 110) / 440; + case 3: return (m_bandwidth - 20) / 80; + case 4: return (m_harmonics / 6.0); + case 5: return m_reduction / 20; + } } // NB! The max name length for VST parameter names, labels @@ -134,7 +132,16 @@ void Devuvuzelator::getParameterDisplay(VstInt32 index, char *label) { - snprintf(label, kVstMaxParamStrLen, "%f", getParameter(index)); + float *params[NumParams] = { + m_low, + m_high, + m_fundamental, + m_bandwidth, + m_harmonics, + m_reduction, + }; + + snprintf(label, kVstMaxParamStrLen, "%f", *params[index]); } void @@ -277,71 +284,6 @@ } } -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 low = -35; - double high = -20; - - if (m_low) low = *m_low; - if (m_high) high = *m_high; - - int harmonics = 3; - if (m_harmonics) harmonics = int(*m_harmonics + 0.5); - - double fun = 200; - if (m_fundamental) fun = *m_fundamental; - - double bw = 40; - if (m_bandwidth) bw = *m_bandwidth; - - double lowfun = fun - bw/2; - double highfun = fun + bw+2; - - double reduction = 10; - if (m_reduction) reduction = *m_reduction; - - for (int h = 0; h < harmonics; ++h) { - - double lowfreq = lowfun * (h+1); - double highfreq = highfun * (h+1); - - int lowbin = (m_fftsize * lowfreq) / m_sampleRate; - int highbin = (m_fftsize * highfreq) / m_sampleRate; - - for (int i = lowbin; i <= highbin; ++i) { - ratios[i] = 1.0; - double db = 10 * log10(mags[i]); - if (db > low && db < high) { - double r = reduction; - ratios[i] = pow(10, -r / 10); - } - } - } - - for (int i = 0; i < hs-1; ++i) { - if (ratios[i] == 1.0 && ratios[i+1] < 1.0) { - ratios[i] = (ratios[i+1] + 1) / 2; - } else if (ratios[i] < 1.0 && ratios[i+1] == 1.0) { - ratios[i+1] = (ratios[i] + 1) / 2; - ++i; - } - } - - for (int i = 0; i < hs; ++i) { - m_real[i] *= ratios[i]; - m_imag[i] *= ratios[i]; - } -} - // FFT implementation by Don Cross, public domain. // This version scales the forward transform. @@ -466,3 +408,5 @@ return new Devuvuzelator(audioMaster); } +#include "devuvuzelator.cpp" + diff -r fe4c331213c5 -r 0d2126c32309 devuvuzelator.cpp --- a/devuvuzelator.cpp Thu Jun 10 21:39:32 2010 +0100 +++ b/devuvuzelator.cpp Fri Jun 11 10:31:29 2010 +0100 @@ -1,319 +1,5 @@ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ -#include -#include -#include -#include - -#define FFTSIZE 1024 - -class Devuvuzelator -{ -public: - static const LADSPA_Descriptor *getDescriptor(unsigned long index); - -private: - Devuvuzelator(int sampleRate); - ~Devuvuzelator(); - - enum { - InputPort = 0, - OutputPort = 1, - LowPort = 2, - HighPort = 3, - FundamentalPort = 4, - BandwidthPort = 5, - HarmonicsPort = 6, - ReductionPort = 7, - PortCount = 8, - }; - - 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(); - - 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_high; - float *m_low; - float *m_fundamental; - float *m_bandwidth; - float *m_harmonics; - float *m_reduction; - - const int m_fftsize; - 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; -}; - -const char *const -Devuvuzelator::portNames[PortCount] = -{ - "Input", - "Output", - "Low threshold (dB)", - "High threshold (dB)", - "Fundamental frequency (Hz)", - "Bandwidth of fundamental (Hz)", - "Number of partials", - "Reduction (dB)", -}; - -const LADSPA_PortDescriptor -Devuvuzelator::ports[PortCount] = -{ - LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, - LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, -}; - -const LADSPA_PortRangeHint -Devuvuzelator::hints[PortCount] = -{ - { 0, 0, 0 }, - { 0, 0, 0 }, - { LADSPA_HINT_DEFAULT_MIDDLE | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, -80, 0 }, - { LADSPA_HINT_DEFAULT_HIGH | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, -80, 0 }, - { LADSPA_HINT_DEFAULT_LOW | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 110, 550 }, - { LADSPA_HINT_DEFAULT_MIDDLE | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 20, 100 }, - { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 6 }, - { LADSPA_HINT_DEFAULT_MIDDLE | - LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 20 }, -}; - -const LADSPA_Properties -Devuvuzelator::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; - -const LADSPA_Descriptor -Devuvuzelator::ladspaDescriptor = -{ - 0, // "Unique" ID - "devuvuzelator", // Label - properties, - "Devuvuzelator", // Name - "Queen Mary, University of London", // Maker - "All Rights Reserved", // Copyright - PortCount, - ports, - portNames, - hints, - 0, // Implementation data - instantiate, - connectPort, - activate, - run, - 0, // Run adding - 0, // Set run adding gain - deactivate, - cleanup -}; - -const LADSPA_Descriptor * -Devuvuzelator::getDescriptor(unsigned long index) -{ - if (index == 0) return &ladspaDescriptor; - return 0; -} - -Devuvuzelator::Devuvuzelator(int sampleRate) : - m_sampleRate(sampleRate), - m_input(0), - m_output(0), - m_low(0), - m_high(0), - m_fftsize(FFTSIZE), - m_increment(m_fftsize/4), - m_fill(0), - m_read(0) -{ - m_buffer = new float[m_fftsize]; - m_outacc = new float[m_fftsize * 2]; - m_real = new double[m_fftsize]; - m_imag = new double[m_fftsize]; - m_window = new double[m_fftsize]; - - for (int i = 0; i < m_fftsize; ++i) { - m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_fftsize); - } - - reset(); -} - -Devuvuzelator::~Devuvuzelator() -{ - delete[] m_buffer; - delete[] m_outacc; - delete[] m_real; - delete[] m_imag; - delete[] m_window; -} - -LADSPA_Handle -Devuvuzelator::instantiate(const LADSPA_Descriptor *, unsigned long rate) -{ - Devuvuzelator *devuvu = new Devuvuzelator(rate); - return devuvu; -} - -void -Devuvuzelator::connectPort(LADSPA_Handle handle, - unsigned long port, LADSPA_Data *location) -{ - Devuvuzelator *devuvu = (Devuvuzelator *)handle; - - float **ports[PortCount] = { - &devuvu->m_input, - &devuvu->m_output, - &devuvu->m_low, - &devuvu->m_high, - &devuvu->m_fundamental, - &devuvu->m_bandwidth, - &devuvu->m_harmonics, - &devuvu->m_reduction, - }; - - *ports[port] = (float *)location; -} - -void -Devuvuzelator::activate(LADSPA_Handle handle) -{ - Devuvuzelator *devuvu = (Devuvuzelator *)handle; - devuvu->reset(); -} - -void -Devuvuzelator::run(LADSPA_Handle handle, unsigned long samples) -{ - Devuvuzelator *devuvu = (Devuvuzelator *)handle; - devuvu->runImpl(samples); -} - -void -Devuvuzelator::deactivate(LADSPA_Handle handle) -{ - activate(handle); // both functions just reset the plugin -} - -void -Devuvuzelator::cleanup(LADSPA_Handle handle) -{ - delete (Devuvuzelator *)handle; -} - -void -Devuvuzelator::reset() -{ - for (int i = 0; i < m_fftsize; ++i) { - m_buffer[i] = 0.f; - } - for (int i = 0; i < m_fftsize*2; ++i) { - m_outacc[i] = 0.f; - } - m_fill = 0; - m_read = 0; -} - -void -Devuvuzelator::runImpl(unsigned long sampleCount) -{ - if (!m_input || !m_output) return; - - int ii = 0; - int oi = 0; - - while (ii < sampleCount) { - - m_output[oi++] = m_outacc[m_read++] / 1.5f; - - if (m_fill == m_fftsize) { - - processFrame(); - - for (int j = m_increment; j < m_fftsize; ++j) { - m_buffer[j - m_increment] = m_buffer[j]; - } - - for (int j = m_increment; j < m_fftsize*2; ++j) { - m_outacc[j - m_increment] = m_outacc[j]; - } - - for (int j = m_fftsize*2 - m_increment; j < m_fftsize*2; ++j) { - m_outacc[j] = 0.f; - } - - m_fill -= m_increment; - m_read -= m_increment; - } - - m_buffer[m_fill++] = m_input[ii++]; - } -} - -void -Devuvuzelator::processFrame() -{ - double *frame = (double *)alloca(m_fftsize * sizeof(double)); - int ix = m_fftsize/2; - for (int i = 0; i < m_fftsize; ++i) { - frame[ix++] = m_buffer[i] * m_window[i]; - if (ix == m_fftsize) ix = 0; - } - - fft(m_fftsize, false, frame, 0, m_real, m_imag); - - processSpectralFrame(); - - for (int i = 0; i < m_fftsize/2-1; ++i) { - m_real[m_fftsize-i] = m_real[i+1]; - m_imag[m_fftsize-i] = -m_imag[i+1]; - } - - double *spare = (double *)alloca(m_fftsize * sizeof(double)); - fft(m_fftsize, true, m_real, m_imag, frame, spare); - - ix = m_fftsize/2; - for (int i = 0; i < m_fftsize; ++i) { - m_outacc[m_fftsize + i] += frame[ix++] * m_window[i]; - if (ix == m_fftsize) ix = 0; - } -} - void Devuvuzelator::processSpectralFrame() { @@ -341,20 +27,24 @@ if (m_bandwidth) bw = *m_bandwidth; double lowfun = fun - bw/2; - double highfun = fun + bw+2; + double highfun = fun + bw/2; double reduction = 10; if (m_reduction) reduction = *m_reduction; - for (int h = 0; h < harmonics; ++h) { + for (int h = 1; h <= harmonics; ++h) { - double lowfreq = lowfun * (h+1); - double highfreq = highfun * (h+1); + double lowfreq = lowfun * h; + double highfreq = highfun * h; - int lowbin = (m_fftsize * lowfreq) / m_sampleRate; - int highbin = (m_fftsize * highfreq) / m_sampleRate; + int lowbin = 0.5 + (m_fftsize * lowfreq) / m_sampleRate; + int highbin = 0.5 + (m_fftsize * highfreq) / m_sampleRate; + +// std::cerr << "partials " << h << ": freqs " << lowfreq << "->" +// << highfreq << ", bins " << lowbin << "->" << highbin << std::endl; for (int i = lowbin; i <= highbin; ++i) { +// std::cerr << "bin " << i << " freq " << (m_sampleRate * i) / m_fftsize << std::endl; ratios[i] = 1.0; double db = 10 * log10(mags[i]); if (db > low && db < high) { @@ -363,7 +53,7 @@ } } } - +/* for (int i = 0; i < hs-1; ++i) { if (ratios[i] == 1.0 && ratios[i+1] < 1.0) { ratios[i] = (ratios[i+1] + 1) / 2; @@ -372,134 +62,10 @@ ++i; } } - +*/ for (int i = 0; i < hs; ++i) { m_real[i] *= ratios[i]; m_imag[i] *= ratios[i]; } } -// 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); -}