annotate devuvuzelator-vst.cpp @ 4:d90abfa9585a

* Adaptive method
author Chris Cannam
date Fri, 11 Jun 2010 15:38:44 +0100
parents 8b79175c9f02
children 45bcfa3d5da7
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@2 3 #define _USE_MATH_DEFINES
Chris@2 4
Chris@0 5 #include <iostream>
Chris@0 6 #include <cmath>
Chris@2 7 #include <cstdio>
Chris@2 8 #include <malloc.h>
Chris@0 9
Chris@2 10 #include "public.sdk/source/vst2.x/audioeffect.h"
Chris@2 11
Chris@2 12 #define snprintf _snprintf
Chris@2 13 #define alloca _alloca
Chris@0 14
Chris@4 15 #define FFTSIZE 4096
Chris@4 16 #define WINSIZE 1024
Chris@4 17
Chris@4 18 #include "median.h"
Chris@0 19
Chris@0 20 class Devuvuzelator : public AudioEffect
Chris@0 21 {
Chris@0 22 enum {
Chris@4 23 FundamentalParam = 1,
Chris@4 24 BandwidthParam = 2,
Chris@4 25 HarmonicsParam = 3,
Chris@4 26 ReductionParam = 4,
Chris@4 27 NumParams = 5
Chris@0 28 };
Chris@0 29
Chris@0 30 public:
Chris@0 31 Devuvuzelator(audioMasterCallback cb);
Chris@0 32 ~Devuvuzelator();
Chris@0 33
Chris@0 34 virtual void getEffectName(char *n) {
Chris@0 35 vst_strncpy(n, "Devuvuzelator", kVstMaxEffectNameLen);
Chris@0 36 }
Chris@0 37 virtual void getProductString(char *n) {
Chris@0 38 vst_strncpy(n, "Devuvuzelator", kVstMaxProductStrLen);
Chris@0 39 }
Chris@0 40 virtual void getVendorString(char *n) {
Chris@0 41 vst_strncpy(n, "Queen Mary, University of London", kVstMaxVendorStrLen);
Chris@0 42 }
Chris@0 43
Chris@0 44 virtual void setParameter(VstInt32 index, float value);
Chris@0 45 virtual float getParameter(VstInt32 index);
Chris@0 46 virtual void getParameterLabel(VstInt32 index, char* label);
Chris@0 47 virtual void getParameterDisplay(VstInt32 index, char* text);
Chris@0 48 virtual void getParameterName(VstInt32 index, char* text);
Chris@0 49
Chris@0 50 virtual void setSampleRate (float sampleRate) {
Chris@0 51 m_sampleRate = sampleRate;
Chris@0 52 AudioEffect::setSampleRate(sampleRate);
Chris@0 53 }
Chris@0 54
Chris@0 55 virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames) {
Chris@0 56 m_input = inputs[0];
Chris@0 57 m_output = outputs[0];
Chris@0 58 runImpl(sampleFrames);
Chris@0 59 }
Chris@0 60
Chris@0 61 void reset();
Chris@0 62 void window(float *);
Chris@0 63 void runImpl(unsigned long);
Chris@0 64 void processFrame();
Chris@0 65 void processSpectralFrame();
Chris@0 66
Chris@0 67 static void fft(unsigned int n, bool inverse,
Chris@0 68 double *ri, double *ii, double *ro, double *io);
Chris@0 69
Chris@2 70 float m_sampleRate;
Chris@0 71 float *m_input;
Chris@0 72 float *m_output;
Chris@0 73
Chris@1 74 float m_low;
Chris@0 75 float m_high;
Chris@0 76 float m_fundamental;
Chris@0 77 float m_bandwidth;
Chris@2 78 int m_harmonics;
Chris@0 79 float m_reduction;
Chris@0 80
Chris@0 81 const int m_fftsize;
Chris@4 82 const int m_winsize;
Chris@0 83 const int m_increment;
Chris@0 84 int m_fill;
Chris@0 85 int m_read;
Chris@0 86 float *m_buffer;
Chris@0 87 float *m_outacc;
Chris@0 88 double *m_real;
Chris@0 89 double *m_imag;
Chris@0 90 double *m_window;
Chris@4 91 MedianFilter<double> **m_medians;
Chris@0 92 };
Chris@0 93
Chris@1 94 // VST params 0->1
Chris@1 95
Chris@0 96 void
Chris@0 97 Devuvuzelator::setParameter(VstInt32 index, float value)
Chris@0 98 {
Chris@1 99 switch (index) {
Chris@4 100 case 0: m_fundamental = 50 + 720 * value; break;
Chris@4 101 case 1: m_bandwidth = 20 + 80 * value; break;
Chris@4 102 case 2: m_harmonics = int(value * 6 + 0.5); break;
Chris@4 103 case 3: m_reduction = 100 * value; break;
Chris@1 104 }
Chris@0 105 }
Chris@0 106
Chris@0 107 float
Chris@0 108 Devuvuzelator::getParameter(VstInt32 index)
Chris@0 109 {
Chris@1 110 switch (index) {
Chris@4 111 case 0: return (m_fundamental - 50) / 720;
Chris@4 112 case 1: return (m_bandwidth - 20) / 80;
Chris@4 113 case 2: return (m_harmonics / 6.f);
Chris@4 114 case 3: return m_reduction / 100;
Chris@1 115 }
Chris@4 116 return 0;
Chris@0 117 }
Chris@0 118
Chris@0 119 // NB! The max name length for VST parameter names, labels
Chris@0 120 // (i.e. units) and display values (i.e. string renderings of current
Chris@0 121 // value) is a rather amazing 8 bytes
Chris@0 122
Chris@0 123 void
Chris@0 124 Devuvuzelator::getParameterLabel(VstInt32 index, char *label)
Chris@0 125 {
Chris@0 126 const char *units[NumParams] = {
Chris@0 127 "Hz",
Chris@0 128 "Hz",
Chris@0 129 "",
Chris@4 130 "%",
Chris@0 131 };
Chris@0 132
Chris@0 133 vst_strncpy(label, units[index], kVstMaxParamStrLen);
Chris@0 134 }
Chris@0 135
Chris@0 136 void
Chris@0 137 Devuvuzelator::getParameterDisplay(VstInt32 index, char *label)
Chris@0 138 {
Chris@4 139 switch (index) {
Chris@4 140 case 0: snprintf(label, kVstMaxParamStrLen, "%f", m_fundamental); break;
Chris@4 141 case 1: snprintf(label, kVstMaxParamStrLen, "%f", m_bandwidth); break;
Chris@4 142 case 2: snprintf(label, kVstMaxParamStrLen, "%d", m_harmonics); break;
Chris@4 143 case 3: snprintf(label, kVstMaxParamStrLen, "%f", m_reduction); break;
Chris@4 144 }
Chris@0 145 }
Chris@0 146
Chris@0 147 void
Chris@0 148 Devuvuzelator::getParameterName(VstInt32 index, char *label)
Chris@0 149 {
Chris@0 150 const char *names[NumParams] = {
Chris@0 151 "Pitch",
Chris@0 152 "B/W",
Chris@0 153 "Partials",
Chris@0 154 "Reductn",
Chris@0 155 };
Chris@0 156
Chris@0 157 vst_strncpy(label, names[index], kVstMaxParamStrLen);
Chris@0 158 }
Chris@0 159
Chris@0 160 Devuvuzelator::Devuvuzelator(audioMasterCallback cb) :
Chris@0 161 AudioEffect(cb, 0, NumParams),
Chris@0 162 m_sampleRate(0),
Chris@0 163 m_input(0),
Chris@0 164 m_output(0),
Chris@0 165 m_fftsize(FFTSIZE),
Chris@0 166 m_increment(m_fftsize/4),
Chris@0 167 m_fill(0),
Chris@0 168 m_read(0)
Chris@0 169 {
Chris@4 170 m_buffer = new float[m_winsize];
Chris@4 171 m_outacc = new float[m_winsize * 2];
Chris@4 172 m_window = new double[m_winsize];
Chris@0 173 m_real = new double[m_fftsize];
Chris@0 174 m_imag = new double[m_fftsize];
Chris@4 175 m_medians = new MedianFilter<double> *[m_fftsize/2+1];
Chris@0 176
Chris@4 177 for (int i = 0; i < m_winsize; ++i) {
Chris@4 178 m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize);
Chris@4 179 }
Chris@4 180 for (int i = 0; i < m_fftsize/2+1; ++i) {
Chris@4 181 m_medians[i] = 0;
Chris@0 182 }
Chris@0 183
Chris@4 184 m_fundamental = 230;
Chris@0 185 m_bandwidth = 60;
Chris@0 186 m_harmonics = 3;
Chris@4 187 m_reduction = 30;
Chris@0 188
Chris@2 189 setUniqueID('qmvz');
Chris@0 190 setNumInputs(1);
Chris@0 191 setNumOutputs(1);
Chris@0 192 canProcessReplacing(true);
Chris@0 193 canDoubleReplacing(false);
Chris@0 194
Chris@0 195 reset();
Chris@0 196 }
Chris@0 197
Chris@0 198 Devuvuzelator::~Devuvuzelator()
Chris@0 199 {
Chris@0 200 delete[] m_buffer;
Chris@0 201 delete[] m_outacc;
Chris@0 202 delete[] m_real;
Chris@0 203 delete[] m_imag;
Chris@0 204 delete[] m_window;
Chris@4 205 for (int i = 0; i < m_fftsize/2+1; ++i) {
Chris@4 206 delete m_medians[i];
Chris@4 207 }
Chris@4 208 delete[] m_medians;
Chris@0 209 }
Chris@0 210
Chris@0 211 void
Chris@0 212 Devuvuzelator::reset()
Chris@0 213 {
Chris@4 214 for (int i = 0; i < m_winsize; ++i) {
Chris@0 215 m_buffer[i] = 0.f;
Chris@0 216 }
Chris@4 217 for (int i = 0; i < m_winsize*2; ++i) {
Chris@0 218 m_outacc[i] = 0.f;
Chris@0 219 }
Chris@0 220 m_fill = 0;
Chris@0 221 m_read = 0;
Chris@4 222 for (int i = 0; i < m_fftsize/2+1; ++i) {
Chris@4 223 if (m_medians[i]) m_medians[i]->reset();
Chris@4 224 }
Chris@0 225 }
Chris@0 226
Chris@0 227 void
Chris@0 228 Devuvuzelator::runImpl(unsigned long sampleCount)
Chris@0 229 {
Chris@0 230 if (!m_input || !m_output) return;
Chris@0 231
Chris@0 232 int ii = 0;
Chris@0 233 int oi = 0;
Chris@4 234 const int sc = sampleCount;
Chris@0 235
Chris@2 236 while (ii < sc) {
Chris@0 237
Chris@4 238 m_output[oi++] = m_outacc[m_read++];
Chris@0 239
Chris@4 240 if (m_fill == m_winsize) {
Chris@0 241
Chris@0 242 processFrame();
Chris@0 243
Chris@4 244 for (int j = m_increment; j < m_winsize; ++j) {
Chris@0 245 m_buffer[j - m_increment] = m_buffer[j];
Chris@0 246 }
Chris@0 247
Chris@4 248 for (int j = m_increment; j < m_winsize*2; ++j) {
Chris@0 249 m_outacc[j - m_increment] = m_outacc[j];
Chris@0 250 }
Chris@0 251
Chris@4 252 for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) {
Chris@0 253 m_outacc[j] = 0.f;
Chris@0 254 }
Chris@0 255
Chris@0 256 m_fill -= m_increment;
Chris@0 257 m_read -= m_increment;
Chris@0 258 }
Chris@0 259
Chris@0 260 m_buffer[m_fill++] = m_input[ii++];
Chris@0 261 }
Chris@0 262 }
Chris@0 263
Chris@0 264 void
Chris@0 265 Devuvuzelator::processFrame()
Chris@0 266 {
Chris@0 267 double *frame = (double *)alloca(m_fftsize * sizeof(double));
Chris@0 268 for (int i = 0; i < m_fftsize; ++i) {
Chris@4 269 frame[i] = 0.0;
Chris@4 270 }
Chris@4 271
Chris@4 272 int ix = m_fftsize - m_winsize/2;
Chris@4 273 while (ix < 0) ix += m_fftsize;
Chris@4 274 for (int i = 0; i < m_winsize; ++i) {
Chris@4 275 frame[ix++] += m_buffer[i] * m_window[i];
Chris@0 276 if (ix == m_fftsize) ix = 0;
Chris@0 277 }
Chris@0 278
Chris@0 279 fft(m_fftsize, false, frame, 0, m_real, m_imag);
Chris@0 280
Chris@0 281 processSpectralFrame();
Chris@0 282
Chris@0 283 for (int i = 0; i < m_fftsize/2-1; ++i) {
Chris@3 284 m_real[m_fftsize-i-1] = m_real[i+1];
Chris@3 285 m_imag[m_fftsize-i-1] = -m_imag[i+1];
Chris@0 286 }
Chris@0 287
Chris@0 288 double *spare = (double *)alloca(m_fftsize * sizeof(double));
Chris@0 289 fft(m_fftsize, true, m_real, m_imag, frame, spare);
Chris@0 290
Chris@4 291 ix = m_fftsize - m_winsize/2;
Chris@4 292 while (ix < 0) ix += m_fftsize;
Chris@4 293 for (int i = 0; i < m_winsize; ++i) {
Chris@4 294 m_outacc[m_winsize + i] += frame[ix++];
Chris@0 295 if (ix == m_fftsize) ix = 0;
Chris@0 296 }
Chris@0 297 }
Chris@0 298
Chris@0 299 // FFT implementation by Don Cross, public domain.
Chris@0 300 // This version scales the forward transform.
Chris@0 301
Chris@0 302 void Devuvuzelator::fft(unsigned int n, bool inverse,
Chris@0 303 double *ri, double *ii, double *ro, double *io)
Chris@0 304 {
Chris@0 305 if (!ri || !ro || !io) return;
Chris@0 306
Chris@0 307 unsigned int bits;
Chris@0 308 unsigned int i, j, k, m;
Chris@0 309 unsigned int blockSize, blockEnd;
Chris@0 310
Chris@0 311 double tr, ti;
Chris@0 312
Chris@0 313 if (n < 2) return;
Chris@0 314 if (n & (n-1)) return;
Chris@0 315
Chris@0 316 double angle = 2.0 * M_PI;
Chris@0 317 if (inverse) angle = -angle;
Chris@0 318
Chris@0 319 for (i = 0; ; ++i) {
Chris@0 320 if (n & (1 << i)) {
Chris@0 321 bits = i;
Chris@0 322 break;
Chris@0 323 }
Chris@0 324 }
Chris@0 325
Chris@0 326 static unsigned int tableSize = 0;
Chris@0 327 static int *table = 0;
Chris@0 328
Chris@0 329 if (tableSize != n) {
Chris@0 330
Chris@0 331 delete[] table;
Chris@0 332
Chris@0 333 table = new int[n];
Chris@0 334
Chris@0 335 for (i = 0; i < n; ++i) {
Chris@0 336
Chris@0 337 m = i;
Chris@0 338
Chris@0 339 for (j = k = 0; j < bits; ++j) {
Chris@0 340 k = (k << 1) | (m & 1);
Chris@0 341 m >>= 1;
Chris@0 342 }
Chris@0 343
Chris@0 344 table[i] = k;
Chris@0 345 }
Chris@0 346
Chris@0 347 tableSize = n;
Chris@0 348 }
Chris@0 349
Chris@0 350 if (ii) {
Chris@0 351 for (i = 0; i < n; ++i) {
Chris@0 352 ro[table[i]] = ri[i];
Chris@0 353 io[table[i]] = ii[i];
Chris@0 354 }
Chris@0 355 } else {
Chris@0 356 for (i = 0; i < n; ++i) {
Chris@0 357 ro[table[i]] = ri[i];
Chris@0 358 io[table[i]] = 0.0;
Chris@0 359 }
Chris@0 360 }
Chris@0 361
Chris@0 362 blockEnd = 1;
Chris@0 363
Chris@0 364 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
Chris@0 365
Chris@0 366 double delta = angle / (double)blockSize;
Chris@0 367 double sm2 = -sin(-2 * delta);
Chris@0 368 double sm1 = -sin(-delta);
Chris@0 369 double cm2 = cos(-2 * delta);
Chris@0 370 double cm1 = cos(-delta);
Chris@0 371 double w = 2 * cm1;
Chris@0 372 double ar[3], ai[3];
Chris@0 373
Chris@0 374 for (i = 0; i < n; i += blockSize) {
Chris@0 375
Chris@0 376 ar[2] = cm2;
Chris@0 377 ar[1] = cm1;
Chris@0 378
Chris@0 379 ai[2] = sm2;
Chris@0 380 ai[1] = sm1;
Chris@0 381
Chris@0 382 for (j = i, m = 0; m < blockEnd; j++, m++) {
Chris@0 383
Chris@0 384 ar[0] = w * ar[1] - ar[2];
Chris@0 385 ar[2] = ar[1];
Chris@0 386 ar[1] = ar[0];
Chris@0 387
Chris@0 388 ai[0] = w * ai[1] - ai[2];
Chris@0 389 ai[2] = ai[1];
Chris@0 390 ai[1] = ai[0];
Chris@0 391
Chris@0 392 k = j + blockEnd;
Chris@0 393 tr = ar[0] * ro[k] - ai[0] * io[k];
Chris@0 394 ti = ar[0] * io[k] + ai[0] * ro[k];
Chris@0 395
Chris@0 396 ro[k] = ro[j] - tr;
Chris@0 397 io[k] = io[j] - ti;
Chris@0 398
Chris@0 399 ro[j] += tr;
Chris@0 400 io[j] += ti;
Chris@0 401 }
Chris@0 402 }
Chris@0 403
Chris@0 404 blockEnd = blockSize;
Chris@0 405 }
Chris@0 406
Chris@0 407 if (!inverse) {
Chris@0 408
Chris@0 409 double denom = (double)n;
Chris@0 410
Chris@0 411 for (i = 0; i < n; i++) {
Chris@0 412 ro[i] /= denom;
Chris@0 413 io[i] /= denom;
Chris@0 414 }
Chris@0 415 }
Chris@0 416 }
Chris@0 417
Chris@0 418 AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
Chris@0 419 {
Chris@0 420 return new Devuvuzelator(audioMaster);
Chris@0 421 }
Chris@0 422
Chris@1 423 #include "devuvuzelator.cpp"
Chris@1 424