Phaser.cpp (16073B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 Phaser.cpp - Phasing and Approximate digital model of an analog JFET phaser. 5 Analog modeling implemented by Ryan Billing aka Transmogrifox. 6 DSP analog modeling theory & practice largely influenced by 7 various CCRMA publications, particularly works by Julius O. Smith. 8 Copyright (C) 2002-2005 Nasca Octavian Paul 9 Copyright (C) 2009-2010 Ryan Billing 10 Copyright (C) 2010-2010 Mark McCurry 11 12 This program is free software; you can redistribute it and/or 13 modify it under the terms of the GNU General Public License 14 as published by the Free Software Foundation; either version 2 15 of the License, or (at your option) any later version. 16 */ 17 18 #include <cmath> 19 #include <algorithm> 20 #include <rtosc/ports.h> 21 #include <rtosc/port-sugar.h> 22 #include "../Misc/Allocator.h" 23 #include "Phaser.h" 24 using namespace std; 25 26 namespace zyn { 27 28 #define rObject Phaser 29 #define rBegin [](const char *msg, rtosc::RtData &d) { 30 #define rEnd } 31 32 #define ucharParamCb(pname) rBegin \ 33 rObject &p = *(rObject*)d.obj; \ 34 if(rtosc_narguments(msg)) \ 35 p.set##pname(rtosc_argument(msg, 0).i); \ 36 else \ 37 d.reply(d.loc, "i", p.P##pname); \ 38 rEnd 39 #define rParamPhaser(name, ...) \ 40 {STRINGIFY(P##name) "::i", rProp(parameter) rMap(min, 0) rMap(max, 127) \ 41 rDefaultDepends(preset) DOC(__VA_ARGS__), NULL, ucharParamCb(name)} 42 43 rtosc::Ports Phaser::ports = { 44 {"preset::i", rProp(parameter) 45 rOptions(Phaser 1, Phaser 2, Phaser 3, Phaser 4, 46 Phaser 5, Phaser 6, 47 APhaser 1, APhaser 2, APhaser 3, APhaser 4, 48 APhaser 5, APhaser 6) 49 rProp(alias) 50 rDefault(0) 51 rDoc("Instrument Presets"), 0, 52 rBegin; 53 rObject *o = (rObject*)d.obj; 54 if(rtosc_narguments(msg)) 55 o->setpreset(rtosc_argument(msg, 0).i); 56 else 57 d.reply(d.loc, "i", o->Ppreset); 58 rEnd}, 59 rEffParVol(rDefaultDepends(preset), 60 rDefault(64), rPreset(3, 39), rPreset(10, 25)), 61 rEffParPan(), 62 rEffPar(lfo.Pfreq, 2, rShort("freq"), 63 rPresets(36, 35, 31, 22, 20, 53, 14, 14, 9, 14, 127, 1), 64 "LFO frequency"), 65 rEffPar(lfo.Prandomness, 3, rShort("rnd."), 66 rPreset(5, 100), rPreset(7, 5), rPresetsAt(9, 10, 10, 10), 67 rDefault(0), "LFO randomness"), 68 rEffParOpt(lfo.PLFOtype, 4, rShort("type"), 69 rPreset(4, tri), rPresetsAt(6, tri, tri), rPreset(11, tri), 70 rDefault(sine), 71 rOptions(sine, tri), "lfo shape"), 72 rEffPar(lfo.Pstereo, 5, rShort("stereo"), 73 rPresetsAt(1, 88, 66, 66, 110, 58), rDefault(64), 74 "Left/right channel phase shift"), 75 rEffPar(Pdepth, 6, rShort("depth"), rLinear(0, 127), 76 rPresets(110, 40, 68, 67, 67, 37, 64, 70, 60, 45, 25, 70), 77 "LFP depth"), 78 rEffPar(Pfb, 7, rShort("fb"), 79 rPresets(64, 64, 107, 10, 78, 78, 40, 40, 40, 80, 16, 40), 80 "Feedback"), 81 rEffPar(Pstages, 8, rLinear(1,12), rShort("stages"), 82 rPresets(1, 3, 2, 5, 10, 3, 4, 6, 8, 7, 8, 12), 83 ""), 84 rParamPhaser(lrcross, rShort("cross"), 85 rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), 86 "Channel routing"), 87 rParamPhaser(offset, rShort("off"), 88 rPresetsAt(6, 10, 10, 10, 10, 100, 10) rDefault(0), 89 "Offset"), 90 rEffParTF(Poutsub, 10, rShort("sub"), 91 rPreset(3, true), rPreset(9, true), rDefault(false), 92 "Invert output"), 93 rParamPhaser(phase, rShort("phase"), 94 rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), 95 rParamPhaser(width, rShort("width"), 96 rPresets(20, 20, 20, 20, 20, 20, 110, 110, 40, 110, 25, 110), ""), 97 rEffParTF(Phyper, 12, rShort("hyp."), 98 rPresetsAt(6, true, true, false, true, false, true), 99 rDefault(false), "Square the LFO"), 100 rEffPar(Pdistortion, 13, rShort("distort"), 101 rPresetsAt(6, 20, 20, 20, 20, 20, 20), rDefault(0), 102 "Distortion"), 103 rEffParTF(Panalog, 14, rShort("analog"), 104 rPresetsAt(6, true, true, true, true, true, true), rDefault(false), 105 "Use analog phaser"), 106 }; 107 #undef rBegin 108 #undef rEnd 109 #undef rObject 110 111 #define PHASER_LFO_SHAPE 2 112 #define ONE_ 0.99999f // To prevent LFO ever reaching 1.0f for filter stability purposes 113 #define ZERO_ 0.00001f // Same idea as above. 114 115 Phaser::Phaser(EffectParams pars) 116 :Effect(pars), lfo(pars.srate, pars.bufsize), old(NULL), xn1(NULL), 117 yn1(NULL), diff(0.0f), oldgain(0.0f), fb(0.0f) 118 { 119 analog_setup(); 120 setpreset(Ppreset); 121 cleanup(); 122 } 123 124 void Phaser::analog_setup() 125 { 126 //model mismatch between JFET devices 127 offset[0] = -0.2509303f; 128 offset[1] = 0.9408924f; 129 offset[2] = 0.998f; 130 offset[3] = -0.3486182f; 131 offset[4] = -0.2762545f; 132 offset[5] = -0.5215785f; 133 offset[6] = 0.2509303f; 134 offset[7] = -0.9408924f; 135 offset[8] = -0.998f; 136 offset[9] = 0.3486182f; 137 offset[10] = 0.2762545f; 138 offset[11] = 0.5215785f; 139 140 barber = 0; //Deactivate barber pole phasing by default 141 142 mis = 1.0f; 143 Rmin = 625.0f; // 2N5457 typical on resistance at Vgs = 0 144 Rmax = 22000.0f; // Resistor parallel to FET 145 Rmx = Rmin / Rmax; 146 Rconst = 1.0f + Rmx; // Handle parallel resistor relationship 147 C = 0.00000005f; // 50 nF 148 CFs = 2.0f * samplerate_f * C; 149 invperiod = 1.0f / buffersize_f; 150 } 151 152 Phaser::~Phaser() 153 { 154 memory.devalloc(old.l); 155 memory.devalloc(old.r); 156 memory.devalloc(xn1.l); 157 memory.devalloc(xn1.r); 158 memory.devalloc(yn1.l); 159 memory.devalloc(yn1.r); 160 } 161 162 /* 163 * Effect output 164 */ 165 void Phaser::out(const Stereo<float *> &input) 166 { 167 if(Panalog) 168 AnalogPhase(input); 169 else 170 normalPhase(input); 171 } 172 173 void Phaser::AnalogPhase(const Stereo<float *> &input) 174 { 175 Stereo<float> gain(0.0f), lfoVal(0.0f), mod(0.0f), g(0.0f), b(0.0f), hpf( 176 0.0f); 177 178 lfo.effectlfoout(&lfoVal.l, &lfoVal.r); 179 mod.l = lfoVal.l * width + (depth - 0.5f); 180 mod.r = lfoVal.r * width + (depth - 0.5f); 181 182 mod.l = limit(mod.l, ZERO_, ONE_); 183 mod.r = limit(mod.r, ZERO_, ONE_); 184 185 if(Phyper) { 186 //Triangle wave squared is approximately sin on bottom, tri on top 187 //Result is exponential sweep more akin to filter in synth with 188 //exponential generator circuitry. 189 mod.l *= mod.l; 190 mod.r *= mod.r; 191 } 192 193 //g.l,g.r is Vp - Vgs. Typical FET drain-source resistance follows constant/[1-sqrt(Vp - Vgs)] 194 mod.l = sqrtf(1.0f - mod.l); 195 mod.r = sqrtf(1.0f - mod.r); 196 197 diff.r = (mod.r - oldgain.r) * invperiod; 198 diff.l = (mod.l - oldgain.l) * invperiod; 199 200 g = oldgain; 201 oldgain = mod; 202 203 for(int i = 0; i < buffersize; ++i) { 204 g.l += diff.l; // Linear interpolation between LFO samples 205 g.r += diff.r; 206 207 Stereo<float> xn(input.l[i] * pangainL, input.r[i] * pangainR); 208 209 if(barber) { 210 g.l += 0.25; 211 g.l -= floorf(g.l); 212 g.r += 0.25; 213 g.r -= floorf(g.r); 214 } 215 216 xn.l = applyPhase(xn.l, g.l, fb.l, hpf.l, yn1.l, xn1.l); 217 xn.r = applyPhase(xn.r, g.r, fb.r, hpf.r, yn1.r, xn1.r); 218 219 220 fb.l = xn.l * feedback; 221 fb.r = xn.r * feedback; 222 efxoutl[i] = xn.l; 223 efxoutr[i] = xn.r; 224 } 225 226 if(Poutsub) { 227 invSignal(efxoutl, buffersize); 228 invSignal(efxoutr, buffersize); 229 } 230 } 231 232 float Phaser::applyPhase(float x, float g, float fb, 233 float &hpf, float *yn1, float *xn1) 234 { 235 for(int j = 0; j < Pstages; ++j) { //Phasing routine 236 mis = 1.0f + offsetpct * offset[j]; 237 238 //This is symmetrical. 239 //FET is not, so this deviates slightly, however sym dist. is 240 //better sounding than a real FET. 241 float d = (1.0f + 2.0f * (0.25f + g) * hpf * hpf * distortion) * mis; 242 Rconst = 1.0f + mis * Rmx; 243 244 // This is 1/R. R is being modulated to control filter fc. 245 float b = (Rconst - g) / (d * Rmin); 246 float gain = (CFs - b) / (CFs + b); 247 yn1[j] = gain * (x + yn1[j]) - xn1[j]; 248 249 //high pass filter: 250 //Distortion depends on the high-pass part of the AP stage. 251 hpf = yn1[j] + (1.0f - gain) * xn1[j]; 252 253 xn1[j] = x; 254 x = yn1[j]; 255 if(j == 1) 256 x += fb; //Insert feedback after first phase stage 257 } 258 return x; 259 } 260 void Phaser::normalPhase(const Stereo<float *> &input) 261 { 262 Stereo<float> gain(0.0f), lfoVal(0.0f); 263 264 lfo.effectlfoout(&lfoVal.l, &lfoVal.r); 265 gain.l = 266 (expf(lfoVal.l 267 * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f); 268 gain.r = 269 (expf(lfoVal.r 270 * PHASER_LFO_SHAPE) - 1) / (expf(PHASER_LFO_SHAPE) - 1.0f); 271 272 gain.l = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.l * depth; 273 gain.r = 1.0f - phase * (1.0f - depth) - (1.0f - phase) * gain.r * depth; 274 275 gain.l = limit(gain.l, ZERO_, ONE_); 276 gain.r = limit(gain.r, ZERO_, ONE_); 277 278 for(int i = 0; i < buffersize; ++i) { 279 float x = (float) i / buffersize_f; 280 float x1 = 1.0f - x; 281 //TODO think about making panning an external feature 282 Stereo<float> xn(input.l[i] * pangainL + fb.l, 283 input.r[i] * pangainR + fb.r); 284 285 Stereo<float> g(gain.l * x + oldgain.l * x1, 286 gain.r * x + oldgain.r * x1); 287 288 xn.l = applyPhase(xn.l, g.l, old.l); 289 xn.r = applyPhase(xn.r, g.r, old.r); 290 291 //Left/Right crossing 292 crossover(xn.l, xn.r, lrcross); 293 294 fb.l = xn.l * feedback; 295 fb.r = xn.r * feedback; 296 efxoutl[i] = xn.l; 297 efxoutr[i] = xn.r; 298 } 299 300 oldgain = gain; 301 302 if(Poutsub) { 303 invSignal(efxoutl, buffersize); 304 invSignal(efxoutr, buffersize); 305 } 306 } 307 308 float Phaser::applyPhase(float x, float g, float *old) 309 { 310 for(int j = 0; j < Pstages * 2; ++j) { //Phasing routine 311 float tmp = old[j]; 312 old[j] = g * tmp + x; 313 x = tmp - g * old[j]; 314 } 315 return x; 316 } 317 318 /* 319 * Cleanup the effect 320 */ 321 void Phaser::cleanup() 322 { 323 fb = oldgain = Stereo<float>(0.0f); 324 for(int i = 0; i < Pstages * 2; ++i) { 325 old.l[i] = 0.0f; 326 old.r[i] = 0.0f; 327 } 328 for(int i = 0; i < Pstages; ++i) { 329 xn1.l[i] = 0.0f; 330 yn1.l[i] = 0.0f; 331 xn1.r[i] = 0.0f; 332 yn1.r[i] = 0.0f; 333 } 334 } 335 336 /* 337 * Parameter control 338 */ 339 void Phaser::setwidth(unsigned char Pwidth) 340 { 341 this->Pwidth = Pwidth; 342 width = ((float)Pwidth / 127.0f); 343 } 344 345 void Phaser::setfb(unsigned char Pfb) 346 { 347 this->Pfb = Pfb; 348 feedback = (float) (Pfb - 64) / 64.2f; 349 } 350 351 void Phaser::setvolume(unsigned char Pvolume) 352 { 353 this->Pvolume = Pvolume; 354 outvolume = Pvolume / 127.0f; 355 if(insertion == 0) 356 volume = 1.0f; 357 else 358 volume = outvolume; 359 } 360 361 void Phaser::setdistortion(unsigned char Pdistortion) 362 { 363 this->Pdistortion = Pdistortion; 364 distortion = (float)Pdistortion / 127.0f; 365 } 366 367 void Phaser::setoffset(unsigned char Poffset) 368 { 369 this->Poffset = Poffset; 370 offsetpct = (float)Poffset / 127.0f; 371 } 372 373 void Phaser::setstages(unsigned char Pstages_) 374 { 375 memory.devalloc(old.l); 376 memory.devalloc(old.r); 377 memory.devalloc(xn1.l); 378 memory.devalloc(xn1.r); 379 memory.devalloc(yn1.l); 380 memory.devalloc(yn1.r); 381 382 Pstages = limit<int>(Pstages_, 1, MAX_PHASER_STAGES); 383 384 old = Stereo<float *>(memory.valloc<float>(Pstages * 2), 385 memory.valloc<float>(Pstages * 2)); 386 387 xn1 = Stereo<float *>(memory.valloc<float>(Pstages), 388 memory.valloc<float>(Pstages)); 389 390 yn1 = Stereo<float *>(memory.valloc<float>(Pstages), 391 memory.valloc<float>(Pstages)); 392 393 cleanup(); 394 } 395 396 void Phaser::setphase(unsigned char Pphase) 397 { 398 this->Pphase = Pphase; 399 phase = (Pphase / 127.0f); 400 } 401 402 void Phaser::setdepth(unsigned char Pdepth) 403 { 404 this->Pdepth = Pdepth; 405 depth = (float)(Pdepth) / 127.0f; 406 } 407 408 unsigned char Phaser::getpresetpar(unsigned char npreset, unsigned int npar) 409 { 410 #define PRESET_SIZE 15 411 #define NUM_PRESETS 12 412 static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { 413 //Phaser 414 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 415 {64, 64, 36, 0, 0, 64, 110, 64, 1, 0, 0, 20, 416 0, 0, 417 0 }, 418 {64, 64, 35, 0, 0, 88, 40, 64, 3, 0, 0, 20, 0, 0, 419 0 }, 420 {64, 64, 31, 0, 0, 66, 68, 107, 2, 0, 0, 20, 0, 0, 421 0 }, 422 {39, 64, 22, 0, 0, 66, 67, 10, 5, 0, 1, 20, 0, 0, 423 0 }, 424 {64, 64, 20, 0, 1, 110, 67, 78, 10, 0, 0, 20, 0, 0, 425 0 }, 426 {64, 64, 53, 100, 0, 58, 37, 78, 3, 0, 0, 20, 0, 0, 427 0 }, 428 //APhaser 429 //0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 430 {64, 64, 14, 0, 1, 64, 64, 40, 4, 10, 0, 110,1, 20, 431 1 }, 432 {64, 64, 14, 5, 1, 64, 70, 40, 6, 10, 0, 110,1, 20, 433 1 }, 434 {64, 64, 9, 0, 0, 64, 60, 40, 8, 10, 0, 40, 0, 20, 435 1 }, 436 {64, 64, 14, 10, 0, 64, 45, 80, 7, 10, 1, 110,1, 20, 437 1 }, 438 {25, 64, 127, 10, 0, 64, 25, 16, 8, 100, 0, 25, 0, 20, 439 1 }, 440 {64, 64, 1, 10, 1, 64, 70, 40, 12, 10, 0, 110,1, 20, 441 1 } 442 }; 443 if(npreset < NUM_PRESETS && npar < PRESET_SIZE) 444 return presets[npreset][npar]; 445 return 0; 446 } 447 448 void Phaser::setpreset(unsigned char npreset) 449 { 450 if(npreset >= NUM_PRESETS) 451 npreset = NUM_PRESETS - 1; 452 for(int n = 0; n != 128; n++) 453 changepar(n, getpresetpar(npreset, n)); 454 Ppreset = npreset; 455 } 456 457 void Phaser::changepar(int npar, unsigned char value) 458 { 459 switch(npar) { 460 case 0: 461 setvolume(value); 462 break; 463 case 1: 464 setpanning(value); 465 break; 466 case 2: 467 lfo.Pfreq = value; 468 lfo.updateparams(); 469 break; 470 case 3: 471 lfo.Prandomness = value; 472 lfo.updateparams(); 473 break; 474 case 4: 475 lfo.PLFOtype = value; 476 lfo.updateparams(); 477 barber = (2 == value); 478 break; 479 case 5: 480 lfo.Pstereo = value; 481 lfo.updateparams(); 482 break; 483 case 6: 484 setdepth(value); 485 break; 486 case 7: 487 setfb(value); 488 break; 489 case 8: 490 setstages(value); 491 break; 492 case 9: 493 setlrcross(value); 494 setoffset(value); 495 break; 496 case 10: 497 Poutsub = min((int)value, 1); 498 break; 499 case 11: 500 setphase(value); 501 setwidth(value); 502 break; 503 case 12: 504 Phyper = min((int)value, 1); 505 break; 506 case 13: 507 setdistortion(value); 508 break; 509 case 14: 510 Panalog = (value!=0); 511 break; 512 } 513 } 514 515 unsigned char Phaser::getpar(int npar) const 516 { 517 switch(npar) { 518 case 0: return Pvolume; 519 case 1: return Ppanning; 520 case 2: return lfo.Pfreq; 521 case 3: return lfo.Prandomness; 522 case 4: return lfo.PLFOtype; 523 case 5: return lfo.Pstereo; 524 case 6: return Pdepth; 525 case 7: return Pfb; 526 case 8: return Pstages; 527 case 9: return Plrcross; 528 return Poffset; //same 529 case 10: return Poutsub; 530 case 11: return Pphase; 531 return Pwidth; //same 532 case 12: return Phyper; 533 case 13: return Pdistortion; 534 case 14: return Panalog; 535 default: return 0; 536 } 537 } 538 539 }