1 /* 2 * ZaMultiCompX2 Stereo multiband compressor 3 * Copyright (C) 2014 Damien Zammit <damien@zamaudio.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * For a full copy of the GNU General Public License see the doc/GPL.txt file. 16 */ 17 18 #include "ZaMultiCompX2Plugin.hpp" 19 20 START_NAMESPACE_DISTRHO 21 22 // ----------------------------------------------------------------------- 23 24 ZaMultiCompX2Plugin::ZaMultiCompX2Plugin() 25 : Plugin(paramCount, 2, 0) 26 { 27 // set default values 28 loadProgram(0); 29 } 30 31 // ----------------------------------------------------------------------- 32 // Init 33 34 void ZaMultiCompX2Plugin::initParameter(uint32_t index, Parameter& parameter) 35 { 36 switch (index) 37 { 38 case paramAttack1: 39 parameter.hints = kParameterIsAutomable; 40 parameter.name = "Attack1"; 41 parameter.symbol = "att1"; 42 parameter.unit = "ms"; 43 parameter.ranges.def = 10.0f; 44 parameter.ranges.min = 0.1f; 45 parameter.ranges.max = 100.0f; 46 break; 47 case paramAttack2: 48 parameter.hints = kParameterIsAutomable; 49 parameter.name = "Attack2"; 50 parameter.symbol = "att2"; 51 parameter.unit = "ms"; 52 parameter.ranges.def = 10.0f; 53 parameter.ranges.min = 0.1f; 54 parameter.ranges.max = 100.0f; 55 break; 56 case paramAttack3: 57 parameter.hints = kParameterIsAutomable; 58 parameter.name = "Attack3"; 59 parameter.symbol = "att3"; 60 parameter.unit = "ms"; 61 parameter.ranges.def = 10.0f; 62 parameter.ranges.min = 0.1f; 63 parameter.ranges.max = 100.0f; 64 break; 65 case paramRelease1: 66 parameter.hints = kParameterIsAutomable; 67 parameter.name = "Release1"; 68 parameter.symbol = "rel1"; 69 parameter.unit = "ms"; 70 parameter.ranges.def = 80.0f; 71 parameter.ranges.min = 1.0f; 72 parameter.ranges.max = 500.0f; 73 break; 74 case paramRelease2: 75 parameter.hints = kParameterIsAutomable; 76 parameter.name = "Release2"; 77 parameter.symbol = "rel2"; 78 parameter.unit = "ms"; 79 parameter.ranges.def = 80.0f; 80 parameter.ranges.min = 1.0f; 81 parameter.ranges.max = 500.0f; 82 break; 83 case paramRelease3: 84 parameter.hints = kParameterIsAutomable; 85 parameter.name = "Release3"; 86 parameter.symbol = "rel3"; 87 parameter.unit = "ms"; 88 parameter.ranges.def = 80.0f; 89 parameter.ranges.min = 1.0f; 90 parameter.ranges.max = 500.0f; 91 break; 92 case paramKnee1: 93 parameter.hints = kParameterIsAutomable; 94 parameter.name = "Knee1"; 95 parameter.symbol = "kn1"; 96 parameter.unit = "dB"; 97 parameter.ranges.def = 0.0f; 98 parameter.ranges.min = 0.0f; 99 parameter.ranges.max = 8.0f; 100 break; 101 case paramKnee2: 102 parameter.hints = kParameterIsAutomable; 103 parameter.name = "Knee2"; 104 parameter.symbol = "kn2"; 105 parameter.unit = "dB"; 106 parameter.ranges.def = 0.0f; 107 parameter.ranges.min = 0.0f; 108 parameter.ranges.max = 8.0f; 109 break; 110 case paramKnee3: 111 parameter.hints = kParameterIsAutomable; 112 parameter.name = "Knee3"; 113 parameter.symbol = "kn3"; 114 parameter.unit = "dB"; 115 parameter.ranges.def = 0.0f; 116 parameter.ranges.min = 0.0f; 117 parameter.ranges.max = 8.0f; 118 break; 119 case paramRatio1: 120 parameter.hints = kParameterIsAutomable | kParameterIsLogarithmic; 121 parameter.name = "Ratio1"; 122 parameter.symbol = "rat1"; 123 parameter.unit = " "; 124 parameter.ranges.def = 4.0f; 125 parameter.ranges.min = 1.0f; 126 parameter.ranges.max = 20.0f; 127 break; 128 case paramRatio2: 129 parameter.hints = kParameterIsAutomable | kParameterIsLogarithmic; 130 parameter.name = "Ratio2"; 131 parameter.symbol = "rat2"; 132 parameter.unit = " "; 133 parameter.ranges.def = 4.0f; 134 parameter.ranges.min = 1.0f; 135 parameter.ranges.max = 20.0f; 136 break; 137 case paramRatio3: 138 parameter.hints = kParameterIsAutomable | kParameterIsLogarithmic; 139 parameter.name = "Ratio3"; 140 parameter.symbol = "rat3"; 141 parameter.unit = " "; 142 parameter.ranges.def = 4.0f; 143 parameter.ranges.min = 1.0f; 144 parameter.ranges.max = 20.0f; 145 break; 146 case paramThresh1: 147 parameter.hints = kParameterIsAutomable; 148 parameter.name = "Threshold 1"; 149 parameter.symbol = "thr1"; 150 parameter.unit = "dB"; 151 parameter.ranges.def = -20.0f; 152 parameter.ranges.min = -60.0f; 153 parameter.ranges.max = 0.0f; 154 break; 155 case paramThresh2: 156 parameter.hints = kParameterIsAutomable; 157 parameter.name = "Threshold 2"; 158 parameter.symbol = "thr2"; 159 parameter.unit = "dB"; 160 parameter.ranges.def = -18.0f; 161 parameter.ranges.min = -60.0f; 162 parameter.ranges.max = 0.0f; 163 break; 164 case paramThresh3: 165 parameter.hints = kParameterIsAutomable; 166 parameter.name = "Threshold 3"; 167 parameter.symbol = "thr3"; 168 parameter.unit = "dB"; 169 parameter.ranges.def = -16.0f; 170 parameter.ranges.min = -60.0f; 171 parameter.ranges.max = 0.0f; 172 break; 173 case paramMakeup1: 174 parameter.hints = kParameterIsAutomable; 175 parameter.name = "Makeup 1"; 176 parameter.symbol = "mak1"; 177 parameter.unit = "dB"; 178 parameter.ranges.def = 0.0f; 179 parameter.ranges.min = 0.0f; 180 parameter.ranges.max = 30.0f; 181 break; 182 case paramMakeup2: 183 parameter.hints = kParameterIsAutomable; 184 parameter.name = "Makeup 2"; 185 parameter.symbol = "mak2"; 186 parameter.unit = "dB"; 187 parameter.ranges.def = 0.0f; 188 parameter.ranges.min = 0.0f; 189 parameter.ranges.max = 30.0f; 190 break; 191 case paramMakeup3: 192 parameter.hints = kParameterIsAutomable; 193 parameter.name = "Makeup 3"; 194 parameter.symbol = "mak3"; 195 parameter.unit = "dB"; 196 parameter.ranges.def = 0.0f; 197 parameter.ranges.min = 0.0f; 198 parameter.ranges.max = 30.0f; 199 break; 200 case paramGainR1: 201 parameter.hints = kParameterIsAutomable | kParameterIsOutput; 202 parameter.name = "Gain Reduction 1"; 203 parameter.symbol = "gr1"; 204 parameter.unit = "dB"; 205 parameter.ranges.def = 0.0f; 206 parameter.ranges.min = 0.0f; 207 parameter.ranges.max = 20.0f; 208 break; 209 case paramGainR2: 210 parameter.hints = kParameterIsAutomable | kParameterIsOutput; 211 parameter.name = "Gain Reduction 2"; 212 parameter.symbol = "gr2"; 213 parameter.unit = "dB"; 214 parameter.ranges.def = 0.0f; 215 parameter.ranges.min = 0.0f; 216 parameter.ranges.max = 20.0f; 217 break; 218 case paramGainR3: 219 parameter.hints = kParameterIsAutomable | kParameterIsOutput; 220 parameter.name = "Gain Reduction 3"; 221 parameter.symbol = "gr3"; 222 parameter.unit = "dB"; 223 parameter.ranges.def = 0.0f; 224 parameter.ranges.min = 0.0f; 225 parameter.ranges.max = 20.0f; 226 break; 227 case paramXover1: 228 parameter.hints = kParameterIsAutomable | kParameterIsLogarithmic; 229 parameter.name = "Crossover freq 1"; 230 parameter.symbol = "xover1"; 231 parameter.unit = "Hz"; 232 parameter.ranges.def = 160.0f; 233 parameter.ranges.min = 20.0f; 234 parameter.ranges.max = 1400.0f; 235 break; 236 case paramXover2: 237 parameter.hints = kParameterIsAutomable | kParameterIsLogarithmic; 238 parameter.name = "Crossover freq 2"; 239 parameter.symbol = "xover2"; 240 parameter.unit = "Hz"; 241 parameter.ranges.def = 1400.0f; 242 parameter.ranges.min = 1400.0f; 243 parameter.ranges.max = 14000.0f; 244 break; 245 case paramToggle1: 246 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 247 parameter.name = "ZamComp 1 ON"; 248 parameter.symbol = "toggle1"; 249 parameter.unit = " "; 250 parameter.ranges.def = 0.0f; 251 parameter.ranges.min = 0.0f; 252 parameter.ranges.max = 1.0f; 253 break; 254 case paramToggle2: 255 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 256 parameter.name = "ZamComp 2 ON"; 257 parameter.symbol = "toggle2"; 258 parameter.unit = " "; 259 parameter.ranges.def = 0.0f; 260 parameter.ranges.min = 0.0f; 261 parameter.ranges.max = 1.0f; 262 break; 263 case paramToggle3: 264 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 265 parameter.name = "ZamComp 3 ON"; 266 parameter.symbol = "toggle3"; 267 parameter.unit = " "; 268 parameter.ranges.def = 0.0f; 269 parameter.ranges.min = 0.0f; 270 parameter.ranges.max = 1.0f; 271 break; 272 case paramListen1: 273 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 274 parameter.name = "Listen 1"; 275 parameter.symbol = "listen1"; 276 parameter.unit = " "; 277 parameter.ranges.def = 0.0f; 278 parameter.ranges.min = 0.0f; 279 parameter.ranges.max = 1.0f; 280 break; 281 case paramListen2: 282 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 283 parameter.name = "Listen 2"; 284 parameter.symbol = "listen2"; 285 parameter.unit = " "; 286 parameter.ranges.def = 0.0f; 287 parameter.ranges.min = 0.0f; 288 parameter.ranges.max = 1.0f; 289 break; 290 case paramListen3: 291 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 292 parameter.name = "Listen 3"; 293 parameter.symbol = "listen3"; 294 parameter.unit = " "; 295 parameter.ranges.def = 0.0f; 296 parameter.ranges.min = 0.0f; 297 parameter.ranges.max = 1.0f; 298 break; 299 case paramGlobalGain: 300 parameter.hints = kParameterIsAutomable; 301 parameter.name = "Master Trim"; 302 parameter.symbol = "globalgain"; 303 parameter.unit = "dB"; 304 parameter.ranges.def = 0.0f; 305 parameter.ranges.min = -12.0f; 306 parameter.ranges.max = 12.0f; 307 break; 308 case paramStereoDet: 309 parameter.hints = kParameterIsAutomable | kParameterIsBoolean; 310 parameter.name = "Detection (MAX/avg)"; 311 parameter.symbol = "stereodet"; 312 parameter.unit = " "; 313 parameter.ranges.def = 1.0f; 314 parameter.ranges.min = 0.0f; 315 parameter.ranges.max = 1.0f; 316 break; 317 case paramOutputLevelL: 318 parameter.hints = kParameterIsOutput; 319 parameter.name = "Output Left"; 320 parameter.symbol = "outl"; 321 parameter.unit = "dB"; 322 parameter.ranges.def = -45.0f; 323 parameter.ranges.min = -45.0f; 324 parameter.ranges.max = 20.0f; 325 break; 326 case paramOutputLevelR: 327 parameter.hints = kParameterIsOutput; 328 parameter.name = "Output Right"; 329 parameter.symbol = "outr"; 330 parameter.unit = "dB"; 331 parameter.ranges.def = -45.0f; 332 parameter.ranges.min = -45.0f; 333 parameter.ranges.max = 20.0f; 334 break; 335 case paramOutputLevelLow: 336 parameter.hints = kParameterIsOutput; 337 parameter.name = "Output low"; 338 parameter.symbol = "outlo"; 339 parameter.unit = "dB"; 340 parameter.ranges.def = -45.0f; 341 parameter.ranges.min = -45.0f; 342 parameter.ranges.max = 20.0f; 343 break; 344 case paramOutputLevelMed: 345 parameter.hints = kParameterIsOutput; 346 parameter.name = "Output medium"; 347 parameter.symbol = "outmed"; 348 parameter.unit = "dB"; 349 parameter.ranges.def = -45.0f; 350 parameter.ranges.min = -45.0f; 351 parameter.ranges.max = 20.0f; 352 break; 353 case paramOutputLevelHigh: 354 parameter.hints = kParameterIsOutput; 355 parameter.name = "Output high"; 356 parameter.symbol = "outhi"; 357 parameter.unit = "dB"; 358 parameter.ranges.def = -45.0f; 359 parameter.ranges.min = -45.0f; 360 parameter.ranges.max = 20.0f; 361 break; 362 } 363 } 364 365 void ZaMultiCompX2Plugin::initProgramName(uint32_t index, String& programName) 366 { 367 switch(index) { 368 case 0: 369 programName = "Zero"; 370 break; 371 case 1: 372 programName = "Presence"; 373 break; 374 } 375 } 376 377 void ZaMultiCompX2Plugin::loadProgram(uint32_t index) 378 { 379 switch(index) { 380 case 0: 381 attack[0] = 10.0; 382 attack[1] = 10.0; 383 attack[2] = 10.0; 384 release[0] = 80.0; 385 release[1] = 80.0; 386 release[2] = 80.0; 387 knee[0] = 0.0; 388 knee[1] = 0.0; 389 knee[2] = 0.0; 390 ratio[0] = 4.0; 391 ratio[1] = 4.0; 392 ratio[2] = 4.0; 393 thresdb[0] = -20.0; 394 thresdb[1] = -18.0; 395 thresdb[2] = -16.0; 396 makeup[0] = 0.0; 397 makeup[1] = 0.0; 398 makeup[2] = 0.0; 399 xover1 = 160.0; 400 xover2 = 1400.0; 401 gainr[0] = 0.0; 402 gainr[1] = 0.0; 403 gainr[2] = 0.0; 404 toggle[0] = 0.0; 405 toggle[1] = 0.0; 406 toggle[2] = 0.0; 407 listen[0] = 0.0; 408 listen[1] = 0.0; 409 listen[2] = 0.0; 410 stereodet = 1.0; 411 globalgain = 0.0; 412 outl = -45.0; 413 outr = -45.0; 414 outlevel[0] = -45.0; 415 outlevel[1] = -45.0; 416 outlevel[2] = -45.0; 417 break; 418 case 1: 419 attack[0] = 10.0; 420 attack[1] = 10.0; 421 attack[2] = 10.0; 422 release[0] = 200.0; 423 release[1] = 200.0; 424 release[2] = 200.0; 425 knee[0] = 3.0; 426 knee[1] = 3.0; 427 knee[2] = 3.0; 428 ratio[0] = 5.0; 429 ratio[1] = 5.0; 430 ratio[2] = 5.0; 431 thresdb[0] = -20.0; 432 thresdb[1] = -18.0; 433 thresdb[2] = -16.0; 434 makeup[0] = 9.0; 435 makeup[1] = 6.0; 436 makeup[2] = 6.0; 437 xover1 = 160.0; 438 xover2 = 1400.0; 439 gainr[0] = 0.0; 440 gainr[1] = 0.0; 441 gainr[2] = 0.0; 442 toggle[0] = 1.0; 443 toggle[1] = 1.0; 444 toggle[2] = 1.0; 445 listen[0] = 0.0; 446 listen[1] = 0.0; 447 listen[2] = 0.0; 448 stereodet = 1.0; 449 globalgain = 0.0; 450 outl = -45.0; 451 outr = -45.0; 452 outlevel[0] = -45.0; 453 outlevel[1] = -45.0; 454 outlevel[2] = -45.0; 455 break; 456 } 457 /* Default variable values */ 458 maxL = 0.f; 459 maxR = 0.f; 460 461 /* reset filter values */ 462 activate(); 463 } 464 465 // ----------------------------------------------------------------------- 466 // Internal data 467 468 float ZaMultiCompX2Plugin::getParameterValue(uint32_t index) const 469 { 470 switch (index) 471 { 472 case paramAttack1: 473 return attack[0]; 474 break; 475 case paramAttack2: 476 return attack[1]; 477 break; 478 case paramAttack3: 479 return attack[2]; 480 break; 481 case paramRelease1: 482 return release[0]; 483 break; 484 case paramRelease2: 485 return release[1]; 486 break; 487 case paramRelease3: 488 return release[2]; 489 break; 490 case paramKnee1: 491 return knee[0]; 492 break; 493 case paramKnee2: 494 return knee[1]; 495 break; 496 case paramKnee3: 497 return knee[2]; 498 break; 499 case paramRatio1: 500 return ratio[0]; 501 break; 502 case paramRatio2: 503 return ratio[1]; 504 break; 505 case paramRatio3: 506 return ratio[2]; 507 break; 508 case paramThresh1: 509 return thresdb[0]; 510 break; 511 case paramThresh2: 512 return thresdb[1]; 513 break; 514 case paramThresh3: 515 return thresdb[2]; 516 break; 517 case paramMakeup1: 518 return makeup[0]; 519 break; 520 case paramMakeup2: 521 return makeup[1]; 522 break; 523 case paramMakeup3: 524 return makeup[2]; 525 break; 526 case paramGainR1: 527 return gainr[0]; 528 break; 529 case paramGainR2: 530 return gainr[1]; 531 break; 532 case paramGainR3: 533 return gainr[2]; 534 break; 535 case paramXover1: 536 return xover1; 537 break; 538 case paramXover2: 539 return xover2; 540 break; 541 case paramToggle1: 542 return toggle[0]; 543 break; 544 case paramToggle2: 545 return toggle[1]; 546 break; 547 case paramToggle3: 548 return toggle[2]; 549 break; 550 case paramListen1: 551 return listen[0]; 552 break; 553 case paramListen2: 554 return listen[1]; 555 break; 556 case paramListen3: 557 return listen[2]; 558 break; 559 case paramGlobalGain: 560 return globalgain; 561 break; 562 case paramStereoDet: 563 return stereodet; 564 break; 565 case paramOutputLevelL: 566 return outl; 567 break; 568 case paramOutputLevelR: 569 return outr; 570 break; 571 case paramOutputLevelLow: 572 return outlevel[0]; 573 break; 574 case paramOutputLevelMed: 575 return outlevel[1]; 576 break; 577 case paramOutputLevelHigh: 578 return outlevel[2]; 579 break; 580 default: 581 return 0.0f; 582 } 583 } 584 585 void ZaMultiCompX2Plugin::setParameterValue(uint32_t index, float value) 586 { 587 switch (index) 588 { 589 case paramAttack1: 590 attack[0] = value; 591 break; 592 case paramAttack2: 593 attack[1] = value; 594 break; 595 case paramAttack3: 596 attack[2] = value; 597 break; 598 case paramRelease1: 599 release[0] = value; 600 break; 601 case paramRelease2: 602 release[1] = value; 603 break; 604 case paramRelease3: 605 release[2] = value; 606 break; 607 case paramKnee1: 608 knee[0] = value; 609 break; 610 case paramKnee2: 611 knee[1] = value; 612 break; 613 case paramKnee3: 614 knee[2] = value; 615 break; 616 case paramRatio1: 617 ratio[0] = value; 618 break; 619 case paramRatio2: 620 ratio[1] = value; 621 break; 622 case paramRatio3: 623 ratio[2] = value; 624 break; 625 case paramThresh1: 626 thresdb[0] = value; 627 break; 628 case paramThresh2: 629 thresdb[1] = value; 630 break; 631 case paramThresh3: 632 thresdb[2] = value; 633 break; 634 case paramMakeup1: 635 makeup[0] = value; 636 break; 637 case paramMakeup2: 638 makeup[1] = value; 639 break; 640 case paramMakeup3: 641 makeup[2] = value; 642 break; 643 case paramGainR1: 644 gainr[0] = value; 645 break; 646 case paramGainR2: 647 gainr[1] = value; 648 break; 649 case paramGainR3: 650 gainr[2] = value; 651 break; 652 case paramXover1: 653 xover1 = value; 654 break; 655 case paramXover2: 656 xover2 = value; 657 break; 658 case paramToggle1: 659 toggle[0] = value; 660 if (value == 0.f) 661 gainr[0] = 0.f; 662 break; 663 case paramToggle2: 664 toggle[1] = value; 665 if (value == 0.f) 666 gainr[1] = 0.f; 667 break; 668 case paramToggle3: 669 toggle[2] = value; 670 if (value == 0.f) 671 gainr[2] = 0.f; 672 break; 673 case paramListen1: 674 listen[0] = value; 675 if (value == 0.f) 676 gainr[0] = 0.f; 677 break; 678 case paramListen2: 679 listen[1] = value; 680 if (value == 0.f) 681 gainr[1] = 0.f; 682 break; 683 case paramListen3: 684 listen[2] = value; 685 if (value == 0.f) 686 gainr[2] = 0.f; 687 break; 688 case paramGlobalGain: 689 globalgain = value; 690 break; 691 case paramStereoDet: 692 stereodet = value; 693 break; 694 case paramOutputLevelL: 695 outl = value; 696 break; 697 case paramOutputLevelR: 698 outr = value; 699 break; 700 case paramOutputLevelLow: 701 outlevel[0] = value; 702 break; 703 case paramOutputLevelMed: 704 outlevel[1] = value; 705 break; 706 case paramOutputLevelHigh: 707 outlevel[2] = value; 708 break; 709 } 710 } 711 712 // ----------------------------------------------------------------------- 713 // Process 714 715 void ZaMultiCompX2Plugin::activate() 716 { 717 int i,j; 718 for (i = 0; i < MAX_COMP; i++) 719 for (j = 0; j < 2; j++) 720 old_yl[j][i]=old_y1[j][i]=old_yg[j][i]=0.f; 721 722 for (j = 0; j < 2; j++) 723 old_ll[j]=old_l1[j]=0.f; 724 725 for (j = 0; j < 2; j++) { 726 for (i = 0; i < MAX_FILT; i++) { 727 simper[j][i].k = 0.f; 728 simper[j][i].g = 0.f; 729 simper[j][i].s[0] = 0.f; 730 simper[j][i].s[1] = 0.f; 731 } 732 } 733 maxL = maxR = 0.f; 734 pos[0] = 0; 735 pos[1] = 0; 736 pos[2] = 0; 737 738 oldxover1 = 0.f; 739 oldxover2 = 0.f; 740 } 741 742 /* 743 * A. Simper's filters 744 * https://cytomic.com/files/dsp/SvfInputMixing.pdf 745 */ 746 747 void ZaMultiCompX2Plugin::linear_svf_set_xover(struct linear_svf *self, float sample_rate, float cutoff, float resonance) 748 { 749 double w; 750 751 self->k = 2. - 2. * resonance; 752 w = M_PI * cutoff / sample_rate; 753 self->g = tan(w); 754 } 755 756 void ZaMultiCompX2Plugin::linear_svf_reset(struct linear_svf *self) 757 { 758 self->s[0] = self->s[1] = 0.f; 759 } 760 761 float ZaMultiCompX2Plugin::run_linear_svf_xover(struct linear_svf *self, float in, float mixlow, float mixhigh) 762 { 763 double v[3]; 764 double g = self->g; 765 double k = self->k; 766 double s0 = self->s[0]; 767 double s1 = self->s[1]; 768 double g2 = g*g; 769 double vhigh = in * mixhigh; 770 double vband = in * 0.75; 771 double vlow = in * mixlow; 772 773 v[0] = in; 774 v[1] = -1. / (1. + g2 + g*k) * (-s0 + g*s1 - g*k*s0 + g2*vband + g*vhigh - g*vlow - g2*k*vlow); 775 v[2] = -1. / (1. + g2 + g*k) * (-g*s0 - s1 - g*vband + g2*vhigh + g*k*vhigh - g2*vlow); 776 self->s[0] = 2. * v[1] - s0; 777 self->s[1] = 2. * v[2] - s1; 778 779 return (float)(vhigh + v[2]); 780 } 781 782 void ZaMultiCompX2Plugin::calc_lr4(float f, int i) 783 { 784 float srate = getSampleRate(); 785 786 linear_svf_set_xover(&simper[0][i], srate, f, 0.25); 787 linear_svf_set_xover(&simper[1][i], srate, f, 0.25); 788 } 789 790 void ZaMultiCompX2Plugin::run_lr4(int i, float in, float *outlo, float *outhi) 791 { 792 *outlo = run_linear_svf_xover(&simper[0][i], in, 1., 0.); 793 *outhi = run_linear_svf_xover(&simper[1][i], in, 0., 1.); 794 } 795 796 void ZaMultiCompX2Plugin::run_comp(int k, float inL, float inR, float *outL, float *outR) 797 { 798 float srate = getSampleRate(); 799 float width = (6.f * knee[k]) + 0.01; 800 float attack_coeff = exp(-1000.f/(attack[k] * srate)); 801 float release_coeff = exp(-1000.f/(release[k] * srate)); 802 int stereolink = (stereodet > 0.5f) ? STEREOLINK_MAX : STEREOLINK_AVERAGE; 803 float checkwidth = 0.f; 804 float cdb=0.f; 805 float Lgain = 1.f; 806 float Rgain = 1.f; 807 float Lxg, Lyg; 808 float Rxg, Ryg; 809 float Lxl, Lyl; 810 float Rxl, Ryl; 811 812 Lyg = Ryg = 0.f; 813 inL = sanitize_denormal(inL); 814 inR = sanitize_denormal(inR); 815 Lxg = (inL==0.f) ? -160.f : to_dB(fabsf(inL)); 816 Rxg = (inR==0.f) ? -160.f : to_dB(fabsf(inR)); 817 Lxg = sanitize_denormal(Lxg); 818 Rxg = sanitize_denormal(Rxg); 819 820 checkwidth = 2.f*fabsf(Lxg-thresdb[k]); 821 if (2.f*(Lxg-thresdb[k]) < -width) { 822 Lyg = Lxg; 823 } else if (checkwidth <= width) { 824 Lyg = Lxg + (1.f/ratio[k]-1.f)*(Lxg-thresdb[k]+width/2.f)*(Lxg-thresdb[k]+width/2.f)/(2.f*width); 825 Lyg = sanitize_denormal(Lyg); 826 } else if (2.f*(Lxg-thresdb[k]) > width) { 827 Lyg = thresdb[k] + (Lxg-thresdb[k])/ratio[k]; 828 Lyg = sanitize_denormal(Lyg); 829 } 830 831 checkwidth = 2.f*fabsf(Rxg-thresdb[k]); 832 if (2.f*(Rxg-thresdb[k]) < -width) { 833 Ryg = Rxg; 834 } else if (checkwidth <= width) { 835 Ryg = Rxg + (1.f/ratio[k]-1.f)*(Rxg-thresdb[k]+width/2.f)*(Rxg-thresdb[k]+width/2.f)/(2.f*width); 836 Ryg = sanitize_denormal(Ryg); 837 } else if (2.f*(Rxg-thresdb[k]) > width) { 838 Ryg = thresdb[k] + (Rxg-thresdb[k])/ratio[k]; 839 Ryg = sanitize_denormal(Ryg); 840 } 841 842 if (stereolink == STEREOLINK_MAX) { 843 Lxl = Rxl = fmaxf(Lxg - Lyg, Rxg - Ryg); 844 } else { 845 Lxl = Rxl = (Lxg - Lyg + Rxg - Ryg) / 2.f; 846 } 847 848 old_yl[0][k] = sanitize_denormal(old_yl[0][k]); 849 old_yl[1][k] = sanitize_denormal(old_yl[1][k]); 850 851 852 if (Lxl < old_yl[0][k]) { 853 Lyl = release_coeff * old_yl[0][k] + (1.f-release_coeff)*Lxl; 854 } else if (Lxl > old_yl[0][k]) { 855 Lyl = attack_coeff * old_yl[0][k]+(1.f-attack_coeff)*Lxl; 856 } else { 857 Lyl = Lxl; 858 } 859 Lyl = sanitize_denormal(Lyl); 860 861 cdb = -Lyl; 862 Lgain = from_dB(cdb); 863 864 if (Rxl < old_yl[1][k]) { 865 Ryl = release_coeff * old_yl[1][k] + (1.f-release_coeff)*Rxl; 866 } else if (Rxl > old_yl[1][k]) { 867 Ryl = attack_coeff * old_yl[1][k]+(1.f-attack_coeff)*Rxl; 868 } else { 869 Ryl = Rxl; 870 } 871 Ryl = sanitize_denormal(Ryl); 872 873 cdb = -Ryl; 874 Rgain = from_dB(cdb); 875 876 if (stereolink == STEREOLINK_MAX) 877 gainr[k] = fmaxf(Lyl, Ryl); 878 else 879 gainr[k] = (Lyl + Ryl) / 2.f; 880 881 *outL = inL * Lgain; 882 *outR = inR * Rgain; 883 884 old_yl[0][k] = Lyl; 885 old_yl[1][k] = Ryl; 886 old_yg[0][k] = Lyg; 887 old_yg[1][k] = Ryg; 888 } 889 890 void ZaMultiCompX2Plugin::pushsample(float sample, int k) 891 { 892 const float rate = 2. * M_PI * 5.; 893 float lpf = rate / (rate + getSampleRate()); 894 895 average[k] += lpf * (sample*sample - average[k]); 896 } 897 898 void ZaMultiCompX2Plugin::run(const float** inputs, float** outputs, uint32_t frames) 899 { 900 float maxxL = 0.; 901 float maxxR = 0.; 902 uint32_t i; 903 904 int tog1 = (toggle[0] > 0.5f) ? 1 : 0; 905 int tog2 = (toggle[1] > 0.5f) ? 1 : 0; 906 int tog3 = (toggle[2] > 0.5f) ? 1 : 0; 907 908 int listen1 = (listen[0] > 0.5f) ? 1 : 0; 909 int listen2 = (listen[1] > 0.5f) ? 1 : 0; 910 int listen3 = (listen[2] > 0.5f) ? 1 : 0; 911 912 if (oldxover1 != xover1) { 913 calc_lr4(xover1, 0); 914 calc_lr4(xover1, 1); 915 oldxover1 = xover1; 916 } 917 918 if (oldxover2 != xover2) { 919 calc_lr4(xover2, 2); 920 calc_lr4(xover2, 3); 921 oldxover2 = xover2; 922 } 923 924 for (i = 0; i < frames; ++i) { 925 float tmp1[2], tmp2[2], tmp3[2]; 926 float fil1[2], fil2[2], fil3[2], fil4[2]; 927 float outL[MAX_COMP+1] = {0.f}; 928 float outR[MAX_COMP+1] = {0.f}; 929 float inl = sanitize_denormal(inputs[0][i]); 930 float inr = sanitize_denormal(inputs[1][i]); 931 inl = (fabsf(inl) < DANGER) ? inl : 0.f; 932 inr = (fabsf(inr) < DANGER) ? inr : 0.f; 933 934 int listenmode = 0; 935 936 // Interleaved channel processing 937 run_lr4(0, inl, &fil1[0], &fil2[0]); 938 run_lr4(1, inr, &fil1[1], &fil2[1]); 939 run_lr4(2, fil2[0], &fil3[0], &fil4[0]); 940 run_lr4(3, fil2[1], &fil3[1], &fil4[1]); 941 942 pushsample(std::max(fil1[0], fil1[1]), 0); 943 outlevel[0] = sqrt(average[0]); 944 outlevel[0] = (outlevel[0] == 0.f) ? -45.0 : to_dB(outlevel[0]); 945 if (tog1) 946 run_comp(0, fil1[0], fil1[1], &outL[0], &outR[0]); 947 948 tmp1[0] = tog1 ? outL[0] * from_dB(makeup[0]) : fil1[0]; 949 tmp1[1] = tog1 ? outR[0] * from_dB(makeup[0]) : fil1[1]; 950 951 pushsample(std::max(fil3[0], fil3[1]), 1); 952 outlevel[1] = sqrt(average[1]); 953 outlevel[1] = (outlevel[1] == 0.f) ? -45.0 : to_dB(outlevel[1]); 954 if (tog2) 955 run_comp(1, fil3[0], fil3[1], &outL[1], &outR[1]); 956 957 tmp2[0] = tog2 ? outL[1] * from_dB(makeup[1]) : fil3[0]; 958 tmp2[1] = tog2 ? outR[1] * from_dB(makeup[1]) : fil3[1]; 959 960 pushsample(std::max(fil4[0], fil4[1]), 2); 961 outlevel[2] = sqrt(average[2]); 962 outlevel[2] = (outlevel[2] == 0.f) ? -45.0 : to_dB(outlevel[2]); 963 if (tog3) 964 run_comp(2, fil4[0], fil4[1], &outL[2], &outR[2]); 965 966 tmp3[0] = tog3 ? outL[2] * from_dB(makeup[2]) : fil4[0]; 967 tmp3[1] = tog3 ? outR[2] * from_dB(makeup[2]) : fil4[1]; 968 969 outputs[0][i] = outputs[1][i] = 0.f; 970 if (listen1) { 971 listenmode = 1; 972 outputs[0][i] += outL[0] * tog1*from_dB(makeup[0]) 973 + (1.-tog1) * tmp1[0]; 974 outputs[1][i] += outR[0] * tog1*from_dB(makeup[0]) 975 + (1.-tog1) * tmp1[1]; 976 } 977 if (listen2) { 978 listenmode = 1; 979 outputs[0][i] += outL[1] * tog2*from_dB(makeup[1]) 980 + (1.-tog2) * tmp2[0]; 981 outputs[1][i] += outR[1] * tog2*from_dB(makeup[1]) 982 + (1.-tog2) * tmp2[1]; 983 } 984 if (listen3) { 985 listenmode = 1; 986 outputs[0][i] += outL[2] * tog3*from_dB(makeup[2]) 987 + (1.-tog3) * tmp3[0]; 988 outputs[1][i] += outR[2] * tog3*from_dB(makeup[2]) 989 + (1.-tog3) * tmp3[1]; 990 } 991 if (!listenmode) { 992 outputs[0][i] = tmp1[0] + tmp2[0] + tmp3[0]; 993 outputs[1][i] = tmp1[1] + tmp2[1] + tmp3[1]; 994 } 995 outputs[0][i] = sanitize_denormal(outputs[0][i]); 996 outputs[1][i] = sanitize_denormal(outputs[1][i]); 997 outputs[0][i] *= from_dB(globalgain); 998 outputs[1][i] *= from_dB(globalgain); 999 1000 maxxL = (fabsf(outputs[0][i]) > maxxL) ? fabsf(outputs[0][i]) : sanitize_denormal(maxxL); 1001 maxxR = (fabsf(outputs[1][i]) > maxxR) ? fabsf(outputs[1][i]) : sanitize_denormal(maxxR); 1002 } 1003 outl = (maxxL == 0.f) ? -160.f : to_dB(maxxL); 1004 outr = (maxxR == 0.f) ? -160.f : to_dB(maxxR); 1005 } 1006 1007 // ----------------------------------------------------------------------- 1008 1009 Plugin* createPlugin() 1010 { 1011 return new ZaMultiCompX2Plugin(); 1012 } 1013 1014 // ----------------------------------------------------------------------- 1015 1016 END_NAMESPACE_DISTRHO 1017