Mercurial > hg > devuvuzelator
view devuvuzelator-vst.cpp @ 8:e15ebd222c63
* (Messy) fixes to VST (e.g. for in-place buffers)
author | Chris Cannam |
---|---|
date | Fri, 11 Jun 2010 20:20:20 +0100 |
parents | 5adad2ca3188 |
children | a1539d4e3b08 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #define _USE_MATH_DEFINES #include <iostream> #include <cmath> #include <cstdio> #include "public.sdk/source/vst2.x/audioeffect.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 Devuvuzelator::setParameter(VstInt32 index, float value) { switch (index) { case 0: m_fundamental = 50 + 720 * value; break; case 1: m_bandwidth = 20 + 80 * value; break; case 2: m_harmonics = int(value * 6 + 0.5); break; case 3: m_reduction = 100 * value; break; } } float Devuvuzelator::getParameter(VstInt32 index) { switch (index) { case 0: return (m_fundamental - 50) / 720; case 1: return (m_bandwidth - 20) / 80; case 2: return (m_harmonics / 6.f); case 3: return m_reduction / 100; } return 0; } // NB! The max name length for VST parameter names, labels // (i.e. units) and display values (i.e. string renderings of current // value) is a rather amazing 8 bytes void Devuvuzelator::getParameterLabel(VstInt32 index, char *label) { const char *units[NumParams] = { "Hz", "Hz", "", "%", }; vst_strncpy(label, units[index], kVstMaxParamStrLen); } void Devuvuzelator::getParameterDisplay(VstInt32 index, char *label) { switch (index) { case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break; case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break; case 2: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break; case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break; } } void Devuvuzelator::getParameterName(VstInt32 index, char *label) { const char *names[NumParams] = { "Pitch", "B/W", "Partials", "Reductn", }; vst_strncpy(label, names[index], kVstMaxParamStrLen); } Devuvuzelator::Devuvuzelator(audioMasterCallback cb) : AudioEffect(cb, 0, NumParams), m_sampleRate(0), m_input(0), m_output(0), m_fftsize(FFTSIZE), m_winsize(WINSIZE), m_increment(m_winsize/2), 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_real = new double[m_fftsize]; m_imag = new double[m_fftsize]; m_medians = new MedianFilter<double> *[m_fftsize/2+1]; for (int i = 0; i < m_winsize; ++i) { m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize); } for (int i = 0; i < m_fftsize/2+1; ++i) { m_medians[i] = 0; } m_fundamental = 230; m_bandwidth = 60; m_harmonics = 3; m_reduction = 30; setUniqueID('qmvz'); setNumInputs(1); setNumOutputs(1); canProcessReplacing(true); canDoubleReplacing(false); reset(); } Devuvuzelator::~Devuvuzelator() { delete[] m_buffer; delete[] m_outacc; delete[] m_frame; delete[] m_spare; delete[] m_real; delete[] m_imag; delete[] m_window; for (int i = 0; i < m_fftsize/2+1; ++i) { delete m_medians[i]; } delete[] m_medians; } void Devuvuzelator::reset() { for (int i = 0; i < m_winsize; ++i) { m_buffer[i] = 0.f; } for (int i = 0; i < m_winsize*2; ++i) { m_outacc[i] = 0.f; } m_fill = 0; m_read = 0; for (int i = 0; i < m_fftsize/2+1; ++i) { if (m_medians[i]) m_medians[i]->reset(); } } void Devuvuzelator::runImpl(unsigned long sampleCount) { 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); fprintf(blah, "%d\n", (int)sampleCount); fflush(blah); */ 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++; 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]; } for (int j = m_increment; j < m_winsize*2; ++j) { m_outacc[j - m_increment] = m_outacc[j]; } for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) { m_outacc[j] = 0.f; } 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; } 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]; } } 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; } int ix = m_fftsize - m_winsize/2; while (ix < 0) ix += m_fftsize; for (int i = 0; i < m_winsize; ++i) { m_frame[ix++] += m_buffer[i] * m_window[i]; if (ix == m_fftsize) ix = 0; } fft(m_fftsize, false, m_frame, 0, m_real, m_imag); // processSpectralFrame(); for (int i = 0; i < m_fftsize/2-1; ++i) { m_real[m_fftsize-i-1] = m_real[i+1]; m_imag[m_fftsize-i-1] = -m_imag[i+1]; } fft(m_fftsize, true, m_real, m_imag, m_frame, m_spare); ix = m_fftsize - m_winsize/2; while (ix < 0) ix += m_fftsize; for (int i = 0; i < m_winsize; ++i) { m_outacc[m_winsize + i] += m_frame[ix++]; 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; } } } AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new Devuvuzelator(audioMaster); } #include "devuvuzelator.cpp"