1 // samplv1_fx.h 2 // 3 /**************************************************************************** 4 Copyright (C) 2012-2021, rncbc aka Rui Nuno Capela. All rights reserved. 5 6 This program is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License 8 as published by the Free Software Foundation; either version 2 9 of the License, or (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License along 17 with this program; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 20 *****************************************************************************/ 21 22 #ifndef __samplv1_fx_h 23 #define __samplv1_fx_h 24 25 #include <cstdint> 26 #include <cstdlib> 27 #include <cmath> 28 29 30 //------------------------------------------------------------------------- 31 // samplv1_fx 32 // 33 // -- borrowed, stirred and refactored from Highlife -- 34 // Copyright (C) 2007 arguru, discodsp.com 35 // 36 37 //------------------------------------------------------------------------- 38 // samplv1_fx_filter - RBJ biquad filter implementation. 39 // 40 // http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt 41 42 class samplv1_fx_filter 43 { 44 public: 45 46 enum Type { 47 Low = 0, High, Band1, Band2, Notch, AllPass, Peak, LoShelf, HiShelf 48 }; 49 50 samplv1_fx_filter(float srate = 44100.0f) m_srate(srate)51 : m_srate(srate) { reset(); } 52 setSampleRate(float srate)53 void setSampleRate(float srate) 54 { m_srate = srate; } sampleRate()55 float sampleRate() const 56 { return m_srate; } 57 58 void reset(Type type, float freq, float q, float gain, bool bwq = false) 59 { 60 reset(); 61 62 // temp vars 63 float alpha, a0, a1, a2, b0, b1, b2; 64 65 // peaking, lowshelf and hishelf 66 if (type >= Peak) { 67 const float amp = ::powf(10.0f, (gain / 40.0f)); 68 const float omega = 2.0f * M_PI * freq / m_srate; 69 const float tsin = ::sinf(omega); 70 const float tcos = ::cosf(omega); 71 const float beta = ::sqrtf(amp) / q; 72 if (bwq) 73 alpha = tsin * ::sinhf(::logf(2.0f) / 2.0f * q * omega / tsin); 74 else 75 alpha = tsin / (2.0f * q); 76 switch (type) { 77 case Peak: 78 // peaking 79 b0 = 1.0f + alpha * amp; 80 b1 = -2.0f * tcos; 81 b2 = 1.0f - alpha * amp; 82 a0 = 1.0f + alpha / amp; 83 a1 = -2.0f * tcos; 84 a2 = 1.0f - alpha / amp; 85 break; 86 case LoShelf: 87 // low-shelf 88 b0 = amp * ((amp + 1.0f) - (amp - 1.0f) * tcos + beta * tsin); 89 b1 = 2.0f * amp *((amp - 1.0f) - (amp + 1.0f) * tcos); 90 b2 = amp * ((amp + 1.0f) - (amp - 1.0f) * tcos - beta * tsin); 91 a0 = (amp + 1.0f) + (amp - 1.0f) * tcos + beta * tsin; 92 a1 = -2.0f *((amp - 1.0f) + (amp + 1.0f) * tcos); 93 a2 = (amp + 1.0f) + (amp - 1.0f) * tcos - beta * tsin; 94 break; 95 case HiShelf: 96 default: 97 // high-shelf 98 b0 = amp * ((amp + 1.0f) + (amp - 1.0f) * tcos + beta * tsin); 99 b1 = -2.0f * amp * ((amp - 1.0f) + (amp + 1.0f) * tcos); 100 b2 = amp * ((amp + 1.0f) + (amp - 1.0f) * tcos - beta * tsin); 101 a0 = (amp + 1.0f) - (amp - 1.0f) * tcos + beta * tsin; 102 a1 = 2.0f * ((amp - 1.0f) - (amp + 1.0f) * tcos); 103 a2 = (amp + 1.0f) - (amp - 1.0f) * tcos - beta * tsin; 104 break; 105 } 106 } else { 107 // other filters 108 const float omega = 2.0f * M_PI * freq / m_srate; 109 const float tsin = ::sinf(omega); 110 const float tcos = ::cosf(omega); 111 if (bwq) 112 alpha = tsin * ::sinhf(::logf(2.0f) / 2.0f * q * omega / tsin); 113 else 114 alpha = tsin / (2.0f * q); 115 switch (type) { 116 case Low: 117 // low-pass 118 b0 = (1.0f - tcos) / 2.0f; 119 b1 = 1.0f - tcos; 120 b2 = (1.0f - tcos) / 2.0f; 121 a0 = 1.0f + alpha; 122 a1 = -2.0f * tcos; 123 a2 = 1.0f - alpha; 124 break; 125 case High: 126 // high-pass 127 b0 = (1.0f + tcos) / 2.0f; 128 b1 = -1.0f - tcos; 129 b2 = (1.0f + tcos) / 2.0f; 130 a0 = 1.0f + alpha; 131 a1 = -2.0f * tcos; 132 a2 = 1.0f - alpha; 133 break; 134 case Band1: 135 // band-pass csg 136 b0 = tsin / 2.0f; 137 b1 = 0.0f; 138 b2 = -tsin / 2.0f; 139 a0 = 1.0f + alpha; 140 a1 = -2.0f * tcos; 141 a2 = 1.0f - alpha; 142 break; 143 case Band2: 144 // band-pass czpg 145 b0 = alpha; 146 b1 = 0.0f; 147 b2 = -alpha; 148 a0 = 1.0f + alpha; 149 a1 = -2.0f * tcos; 150 a2 = 1.0f - alpha; 151 break; 152 case Notch: 153 // notch 154 b0 = 1.0f; 155 b1 = -2.0f * tcos; 156 b2 = 1.0f; 157 a0 = 1.0f + alpha; 158 a1 = -2.0f * tcos; 159 a2 = 1.0f - alpha; 160 break; 161 case AllPass: 162 default: 163 // all-pass 164 b0 = 1.0f - alpha; 165 b1 = -2.0f * tcos; 166 b2 = 1.0f + alpha; 167 a0 = 1.0f + alpha; 168 a1 = -2.0f * tcos; 169 a2 = 1.0f - alpha; 170 break; 171 } 172 } 173 // set filter coeffs 174 m_b0a0 = b0 / a0; 175 m_b1a0 = b1 / a0; 176 m_b2a0 = b2 / a0; 177 m_a1a0 = a1 / a0; 178 m_a2a0 = a2 / a0; 179 }; 180 output(float in)181 float output(float in) 182 { 183 // filter 184 const float out = m_b0a0 * in 185 + m_b1a0 * m_in1 + m_b2a0 * m_in2 186 - m_a1a0 * m_out1 - m_a2a0 * m_out2; 187 // push in/out buffers 188 m_in2 = m_in1; 189 m_in1 = in; 190 m_out2 = m_out1; 191 m_out1 = out; 192 // return output 193 return out; 194 } 195 196 protected: 197 reset()198 void reset() 199 { 200 m_b0a0 = m_b1a0 = m_b2a0 = m_a1a0 = m_a2a0 = 0.0f; 201 m_out1 = m_out2 = 0.0f; 202 m_in1 = m_in2 = 0.0f; 203 } 204 205 private: 206 207 // nominal sample-rate 208 float m_srate; 209 210 // filter coeffs 211 float m_b0a0, m_b1a0, m_b2a0, m_a1a0, m_a2a0; 212 213 // in/out history 214 float m_out1, m_out2, m_in1, m_in2; 215 }; 216 217 218 //------------------------------------------------------------------------- 219 // samplv1_fx_comp - DiscoDSP's "rock da disco" compressor/eq. 220 221 class samplv1_fx_comp 222 { 223 public: 224 225 samplv1_fx_comp(float srate = 44100.0f) m_srate(srate)226 : m_srate(srate), m_peak(0.0f), 227 m_attack(0.0f), m_release(0.0f), 228 m_lo(srate), m_mi(srate), m_hi(srate) {} 229 setSampleRate(float srate)230 void setSampleRate(float srate) 231 { 232 m_srate = srate; 233 234 m_lo.setSampleRate(srate); 235 m_mi.setSampleRate(srate); 236 m_hi.setSampleRate(srate); 237 } 238 sampleRate()239 float sampleRate() const 240 { return m_srate; } 241 reset()242 void reset() 243 { 244 m_peak = 0.0f; 245 246 m_attack = ::expf(-1000.0f / (m_srate * 3.6f)); 247 m_release = ::expf(-1000.0f / (m_srate * 150.0f)); 248 249 // rock-da-house eq. 250 m_lo.reset(samplv1_fx_filter::Peak, 100.0f, 1.0f, 6.0f); 251 m_mi.reset(samplv1_fx_filter::LoShelf, 1000.0f, 1.0f, 3.0f); 252 m_hi.reset(samplv1_fx_filter::HiShelf, 10000.0f, 1.0f, 4.0f); 253 } 254 process(float * in,uint32_t nframes)255 void process(float *in, uint32_t nframes) 256 { 257 // compressor 258 const float threshold = 0.251f; //~= powf(10.0f, -12.0f / 20.0f); 259 const float post_gain = 1.995f; //~= powf(10.0f, 6.0f / 20.0f); 260 // process buffers 261 for (uint32_t i = 0; i < nframes; ++i) { 262 // anti-denormalizer noise 263 const float ad = 1E-14f * float(::rand()); 264 // process 265 const float lo = m_lo.output(m_mi.output(m_hi.output(*in + ad))); 266 // compute peak 267 const float peak = ::fabsf(lo); 268 // compute gain 269 float gain = 1.0f; 270 if (peak > threshold) 271 gain = threshold / peak; 272 // envelope 273 if (m_peak > gain) { 274 m_peak *= m_attack; 275 m_peak += (1.0f - m_attack) * gain; 276 } else { 277 m_peak *= m_release; 278 m_peak += (1.0f - m_release) * gain; 279 } 280 // output 281 *in++ = lo * m_peak * post_gain; 282 } 283 } 284 285 private: 286 287 float m_srate; 288 289 float m_peak; 290 float m_attack; 291 float m_release; 292 293 samplv1_fx_filter m_lo, m_mi, m_hi; 294 }; 295 296 297 //------------------------------------------------------------------------- 298 // samplv1_fx_flanger - Flanger implementation. 299 300 301 class samplv1_fx_flanger 302 { 303 public: 304 samplv1_fx_flanger()305 samplv1_fx_flanger() 306 { reset(); } 307 reset()308 void reset() 309 { 310 for(uint32_t i = 0; i < MAX_SIZE; ++i) 311 m_buffer[i] = 0.0f; 312 313 m_frames = 0; 314 } 315 output(float in,float delay,float feedb)316 float output(float in, float delay, float feedb) 317 { 318 // calculate delay offset 319 float delta = float(m_frames) - delay; 320 // clip lookback buffer-bound 321 if (delta < 0.0f) 322 delta += float(MAX_SIZE); 323 // get index 324 const uint32_t index = uint32_t(delta); 325 // 4 samples hermite 326 const float y0 = m_buffer[(index + 0) & MAX_MASK]; 327 const float y1 = m_buffer[(index + 1) & MAX_MASK]; 328 const float y2 = m_buffer[(index + 2) & MAX_MASK]; 329 const float y3 = m_buffer[(index + 3) & MAX_MASK]; 330 // csi calculate 331 const float c0 = y1; 332 const float c1 = 0.5f * (y2 - y0); 333 const float c2 = y0 - 2.5f * y1 + 2.0f * y2 - 0.5f * y3; 334 const float c3 = 0.5f * (y3 - y0) + 1.5f * (y1 - y2); 335 // compute interpolation x 336 const float x = delta - ::floorf(delta); 337 // get output 338 const float out = ((c3 * x + c2) * x + c1) * x + c0; 339 // add to delay buffer 340 m_buffer[(m_frames++) & MAX_MASK] = in + out * feedb; 341 // return output 342 return out; 343 } 344 process(float * in,uint32_t nframes,float wet,float delay,float feedb,float daft)345 void process(float *in, uint32_t nframes, 346 float wet, float delay, float feedb, float daft) 347 { 348 if (wet < 1E-9f) 349 return; 350 // daft effect 351 if (daft > 0.001f) { 352 delay *= (1.0f - daft); 353 // feedb *= (1.0f - daft); 354 } 355 delay *= float(MAX_SIZE); 356 // process 357 for (uint32_t i = 0; i < nframes; ++i) 358 in[i] += wet * output(in[i], delay, feedb); 359 } 360 361 static const uint32_t MAX_SIZE = (1 << 12); //= 4096; 362 static const uint32_t MAX_MASK = MAX_SIZE - 1; 363 364 private: 365 366 float m_buffer[MAX_SIZE]; 367 368 uint32_t m_frames; 369 }; 370 371 372 //------------------------------------------------------------------------- 373 // samplv1_fx_chorus - Chorus implementation. 374 375 class samplv1_fx_chorus 376 { 377 public: 378 379 samplv1_fx_chorus(float srate = 44100.0f) m_srate(srate)380 : m_srate(srate) { reset(); } 381 setSampleRate(float srate)382 void setSampleRate(float srate) 383 { m_srate = srate; } sampleRate()384 float sampleRate() const 385 { return m_srate; } 386 reset()387 void reset() 388 { 389 m_flang1.reset(); 390 m_flang2.reset(); 391 392 m_lfo = 0.0f; 393 } 394 process(float * in1,float * in2,uint32_t nframes,float wet,float delay,float feedb,float rate,float mod)395 void process(float *in1, float *in2, uint32_t nframes, 396 float wet, float delay, float feedb, float rate, float mod) 397 { 398 if (wet < 1E-9f) 399 return; 400 // constrained feedback 401 feedb *= 0.95f; 402 // calculate delay time 403 const float d0 = 0.5f * delay * float(samplv1_fx_flanger::MAX_SIZE); 404 const float a1 = 0.99f * d0 * mod * mod; 405 const float r2 = 4.0f * M_PI * rate * rate / m_srate; 406 // process 407 for (uint32_t i = 0; i < nframes; ++i) { 408 // modulation 409 const float lfo = a1 * pseudo_sinf(m_lfo); 410 const float delay1 = d0 - lfo; 411 const float delay2 = d0 - lfo * 0.9f; 412 // chorus mix 413 in1[i] += wet * m_flang1.output(in1[i], delay1, feedb); 414 in2[i] += wet * m_flang2.output(in2[i], delay2, feedb); 415 // lfo advance 416 m_lfo += r2; 417 // lfo wrap 418 if (m_lfo >= 1.0f) 419 m_lfo -= 2.0f; 420 } 421 } 422 423 protected: 424 pseudo_sinf(float x)425 float pseudo_sinf(float x) const 426 { 427 x *= x; 428 x -= 1.0f; 429 return x * x; 430 } 431 432 private: 433 434 float m_srate; 435 436 samplv1_fx_flanger m_flang1; 437 samplv1_fx_flanger m_flang2; 438 439 float m_lfo; 440 }; 441 442 443 //------------------------------------------------------------------------- 444 // samplv1_fx_delay - Delay implementation. 445 446 class samplv1_fx_delay 447 { 448 public: 449 450 samplv1_fx_delay(float srate = 44100.0f) m_srate(srate)451 : m_srate(srate) { reset(); } 452 setSampleRate(float srate)453 void setSampleRate(float srate) 454 { m_srate = srate; } sampleRate()455 float sampleRate() const 456 { return m_srate; } 457 reset()458 void reset() 459 { 460 for (uint32_t i = 0; i < MAX_SIZE; ++i) 461 m_buffer[i] = 0.0f; 462 463 m_out = 0.0f; 464 m_frames = 0; 465 } 466 467 void process(float *in, uint32_t nframes, 468 float wet, float delay, float feedb, float bpm = 0.0f) 469 { 470 if (wet < 1E-9f) 471 return; 472 // constrained feedback 473 feedb *= 0.95f; 474 // calculate delay time 475 float delay_time = delay * m_srate; 476 if (bpm > 0.0f) 477 delay_time *= 60.f / bpm; 478 // set integer delay 479 uint32_t ndelay = uint32_t(delay_time); 480 // clamp 481 if (ndelay < MIN_SIZE) 482 ndelay = MIN_SIZE; 483 else 484 if (ndelay > MAX_SIZE) 485 ndelay = MAX_SIZE; 486 // delay process 487 for (uint32_t i = 0; i < nframes; ++i) { 488 const uint32_t j = (m_frames++) & MAX_MASK; 489 m_out = m_buffer[(j - ndelay) & MAX_MASK]; 490 m_buffer[j] = *in + m_out * feedb; 491 *in++ += wet * m_out; 492 } 493 } 494 495 static const uint32_t MIN_SIZE = (1 << 8); //= 256; 496 static const uint32_t MAX_SIZE = (1 << 16); //= 65536; 497 static const uint32_t MAX_MASK = MAX_SIZE - 1; 498 499 private: 500 501 float m_srate; 502 503 float m_buffer[MAX_SIZE]; 504 float m_out; 505 506 uint32_t m_frames; 507 }; 508 509 510 //------------------------------------------------------------------------- 511 // samplv1_fx_allpass - All-pass delay implementation. 512 513 class samplv1_fx_allpass 514 { 515 public: 516 samplv1_fx_allpass()517 samplv1_fx_allpass() 518 { reset(); } 519 reset()520 void reset() 521 { m_out = 0.0f; } 522 output(float in,float delay)523 float output(float in, float delay) 524 { 525 const float a1 = (1.0f - delay) / (1.0f + delay); 526 const float out = m_out - a1 * in; 527 m_out = in + a1 * out; 528 return out; 529 } 530 531 private: 532 533 float m_out; 534 }; 535 536 537 //------------------------------------------------------------------------- 538 // samplv1_fx_phaser - Phaser implementation. 539 540 class samplv1_fx_phaser 541 { 542 public: 543 544 samplv1_fx_phaser(float srate = 44100.0f) m_srate(srate)545 : m_srate(srate) { reset(); } 546 setSampleRate(float srate)547 void setSampleRate(float srate) 548 { m_srate = srate; } sampleRate()549 float sampleRate() const 550 { return m_srate; } 551 reset()552 void reset() 553 { 554 // initialize vars 555 m_lfo_phase = 0.0f; 556 m_out = 0.0f; 557 // reset taps 558 for (uint16_t n = 0; n < MAX_TAPS; ++n) 559 m_taps[n].reset(); 560 } 561 process(float * in,uint32_t nframes,float wet,float rate,float feedb,float depth,float daft)562 void process(float *in, uint32_t nframes, float wet, 563 float rate, float feedb, float depth, float daft) 564 { 565 if (wet < 1E-9f) 566 return; 567 // daft effect 568 if (daft > 0.001f && daft < 1.0f) { 569 rate *= (1.0f - 0.5f * daft); 570 // feedb *= (1.0f - daft); 571 depth *= (1.0f - daft); 572 } 573 depth += 1.0f; 574 // update coeffs 575 const float delay_min = 2.0f * 440.0f / m_srate; 576 const float delay_max = 2.0f * 4400.0f / m_srate; 577 const float lfo_inc = 2.0f * M_PI * rate / m_srate; 578 // anti-denormal noise 579 const float adenormal = 1E-14f * float(::rand()); 580 // sweep... 581 for (uint32_t i = 0; i < nframes; ++i) { 582 // calculate and update phaser lfo 583 const float delay = delay_min + (delay_max - delay_min) 584 * 0.5f * (1.0f + ::sinf(m_lfo_phase)); 585 // increment phase 586 m_lfo_phase += lfo_inc; 587 // positive wrap phase 588 if (m_lfo_phase >= 2.0f * M_PI) 589 m_lfo_phase -= 2.0f * M_PI; 590 // get input 591 m_out = in[i] + adenormal + m_out * feedb; 592 // update filter coeffs and calculate output 593 for (uint16_t n = 0; n < MAX_TAPS; ++n) 594 m_out = m_taps[n].output(m_out, delay); 595 // output 596 in[i] += wet * m_out * depth; 597 } 598 } 599 600 private: 601 602 float m_srate; 603 604 static const uint16_t MAX_TAPS = 6; 605 606 samplv1_fx_allpass m_taps[MAX_TAPS]; 607 608 float m_dmin; 609 float m_dmax; 610 float m_feedb; 611 float m_lfo_phase; 612 float m_lfo_inc; 613 float m_depth; 614 615 float m_out; 616 }; 617 618 619 #endif // __samplv1_fx_h 620 621 // end of samplv1_fx.h 622