changeset 1:0d2126c32309

* split out core code, fix some things
author Chris Cannam
date Fri, 11 Jun 2010 10:31:29 +0100
parents fe4c331213c5
children e621e794011f
files devuvuzelator-ladspa.cpp devuvuzelator-vst.cpp devuvuzelator.cpp
diffstat 3 files changed, 487 insertions(+), 533 deletions(-) [+]
line wrap: on
line diff
--- /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 <ladspa.h>
+#include <alloca.h>
+#include <iostream>
+#include <cmath>
+
+#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"
+
--- 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"
+
--- 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 <ladspa.h>
-#include <alloca.h>
-#include <iostream>
-#include <cmath>
-
-#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);
-}