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