1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 16 сент. 2016 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <core/debug.h> 23 #include <core/colors.h> 24 #include <core/util/Color.h> 25 #include <plugins/compressor.h> 26 27 #define COMP_BUF_SIZE 0x1000 28 #define TRACE_PORT(p) lsp_trace(" port id=%s", (p)->metadata()->id); 29 30 namespace lsp 31 { 32 //------------------------------------------------------------------------- 33 // Compressor base class 34 compressor_base(const plugin_metadata_t & metadata,bool sc,size_t mode)35 compressor_base::compressor_base(const plugin_metadata_t &metadata, bool sc, size_t mode): plugin_t(metadata) 36 { 37 nMode = mode; 38 bSidechain = sc; 39 vChannels = NULL; 40 vCurve = NULL; 41 vTime = NULL; 42 bPause = false; 43 bClear = false; 44 bMSListen = false; 45 fInGain = 1.0f; 46 bUISync = true; 47 48 pBypass = NULL; 49 pInGain = NULL; 50 pOutGain = NULL; 51 pPause = NULL; 52 pClear = NULL; 53 pMSListen = NULL; 54 55 pData = NULL; 56 pIDisplay = NULL; 57 } 58 ~compressor_base()59 compressor_base::~compressor_base() 60 { 61 } 62 init(IWrapper * wrapper)63 void compressor_base::init(IWrapper *wrapper) 64 { 65 plugin_t::init(wrapper); 66 size_t channels = (nMode == CM_MONO) ? 1 : 2; 67 68 // Allocate channels 69 vChannels = new channel_t[channels]; 70 if (vChannels == NULL) 71 return; 72 73 // Allocate temporary buffers 74 size_t buf_size = COMP_BUF_SIZE * sizeof(float); 75 size_t curve_size = (compressor_base_metadata::CURVE_MESH_SIZE) * sizeof(float); 76 size_t history_size = (compressor_base_metadata::TIME_MESH_SIZE) * sizeof(float); 77 size_t allocate = buf_size * channels * 5 + curve_size + history_size + DEFAULT_ALIGN; 78 uint8_t *ptr = new uint8_t[allocate]; 79 if (ptr == NULL) 80 return; 81 pData = ptr; 82 ptr = ALIGN_PTR(ptr, DEFAULT_ALIGN); 83 vCurve = reinterpret_cast<float *>(ptr); 84 ptr += curve_size; 85 vTime = reinterpret_cast<float *>(ptr); 86 ptr += history_size; 87 88 // Initialize channels 89 for (size_t i=0; i<channels; ++i) 90 { 91 channel_t *c = &vChannels[i]; 92 93 if (!c->sSC.init(channels, compressor_base_metadata::REACTIVITY_MAX)) 94 return; 95 if (!c->sSCEq.init(2, 12)) 96 return; 97 c->sSCEq.set_mode(EQM_IIR); 98 c->sSC.set_pre_equalizer(&c->sSCEq); 99 100 c->vIn = reinterpret_cast<float *>(ptr); 101 ptr += buf_size; 102 c->vOut = reinterpret_cast<float *>(ptr); 103 ptr += buf_size; 104 c->vSc = reinterpret_cast<float *>(ptr); 105 ptr += buf_size; 106 c->vEnv = reinterpret_cast<float *>(ptr); 107 ptr += buf_size; 108 c->vGain = reinterpret_cast<float *>(ptr); 109 ptr += buf_size; 110 c->bScListen = false; 111 c->nSync = S_ALL; 112 c->nScType = SCT_FEED_FORWARD; 113 c->fMakeup = 1.0f; 114 c->fFeedback = 0.0f; 115 c->fDryGain = 1.0f; 116 c->fWetGain = 0.0f; 117 c->fDotIn = 0.0f; 118 c->fDotOut = 0.0f; 119 120 c->pIn = NULL; 121 c->pOut = NULL; 122 c->pSC = NULL; 123 124 for (size_t j=0; j<G_TOTAL; ++j) 125 c->pGraph[j] = NULL; 126 127 for (size_t j=0; j<M_TOTAL; ++j) 128 c->pMeter[j] = NULL; 129 130 c->pScType = NULL; 131 c->pScMode = NULL; 132 c->pScLookahead = NULL; 133 c->pScListen = NULL; 134 c->pScSource = NULL; 135 c->pScReactivity = NULL; 136 c->pScPreamp = NULL; 137 c->pScHpfMode = NULL; 138 c->pScHpfFreq = NULL; 139 c->pScLpfMode = NULL; 140 c->pScLpfFreq = NULL; 141 142 c->pMode = NULL; 143 c->pAttackLvl = NULL; 144 c->pReleaseLvl = NULL; 145 c->pAttackTime = NULL; 146 c->pReleaseTime = NULL; 147 c->pRatio = NULL; 148 c->pKnee = NULL; 149 c->pBThresh = NULL; 150 c->pBoost = NULL; 151 c->pMakeup = NULL; 152 c->pDryGain = NULL; 153 c->pWetGain = NULL; 154 c->pCurve = NULL; 155 c->pReleaseOut = NULL; 156 } 157 158 lsp_assert(ptr < &pData[allocate]); 159 160 // Bind ports 161 size_t port_id = 0; 162 163 // Input ports 164 lsp_trace("Binding input ports"); 165 for (size_t i=0; i<channels; ++i) 166 { 167 TRACE_PORT(vPorts[port_id]); 168 vChannels[i].pIn = vPorts[port_id++]; 169 } 170 171 // Input ports 172 lsp_trace("Binding output ports"); 173 for (size_t i=0; i<channels; ++i) 174 { 175 TRACE_PORT(vPorts[port_id]); 176 vChannels[i].pOut = vPorts[port_id++]; 177 } 178 179 // Input ports 180 if (bSidechain) 181 { 182 lsp_trace("Binding sidechain ports"); 183 for (size_t i=0; i<channels; ++i) 184 { 185 TRACE_PORT(vPorts[port_id]); 186 vChannels[i].pSC = vPorts[port_id++]; 187 } 188 } 189 190 // Common ports 191 lsp_trace("Binding common ports"); 192 TRACE_PORT(vPorts[port_id]); 193 pBypass = vPorts[port_id++]; 194 TRACE_PORT(vPorts[port_id]); 195 pInGain = vPorts[port_id++]; 196 TRACE_PORT(vPorts[port_id]); 197 pOutGain = vPorts[port_id++]; 198 TRACE_PORT(vPorts[port_id]); 199 pPause = vPorts[port_id++]; 200 TRACE_PORT(vPorts[port_id]); 201 pClear = vPorts[port_id++]; 202 if (nMode == CM_MS) 203 { 204 TRACE_PORT(vPorts[port_id]); 205 pMSListen = vPorts[port_id++]; 206 } 207 208 // Sidechain ports 209 lsp_trace("Binding sidechain ports"); 210 for (size_t i=0; i<channels; ++i) 211 { 212 channel_t *c = &vChannels[i]; 213 214 if ((i > 0) && (nMode == CM_STEREO)) 215 { 216 channel_t *sc = &vChannels[0]; 217 c->pScType = sc->pScType; 218 c->pScSource = sc->pScSource; 219 c->pScLookahead = sc->pScLookahead; 220 c->pScMode = sc->pScMode; 221 c->pScListen = sc->pScListen; 222 c->pScReactivity = sc->pScReactivity; 223 c->pScPreamp = sc->pScPreamp; 224 c->pScHpfMode = sc->pScHpfMode; 225 c->pScHpfFreq = sc->pScHpfFreq; 226 c->pScLpfMode = sc->pScLpfMode; 227 c->pScLpfFreq = sc->pScLpfFreq; 228 } 229 else 230 { 231 TRACE_PORT(vPorts[port_id]); 232 c->pScType = vPorts[port_id++]; 233 TRACE_PORT(vPorts[port_id]); 234 c->pScMode = vPorts[port_id++]; 235 TRACE_PORT(vPorts[port_id]); 236 c->pScLookahead = vPorts[port_id++]; 237 TRACE_PORT(vPorts[port_id]); 238 c->pScListen = vPorts[port_id++]; 239 if (nMode != CM_MONO) 240 { 241 TRACE_PORT(vPorts[port_id]); 242 c->pScSource = vPorts[port_id++]; 243 } 244 TRACE_PORT(vPorts[port_id]); 245 c->pScReactivity = vPorts[port_id++]; 246 TRACE_PORT(vPorts[port_id]); 247 c->pScPreamp = vPorts[port_id++]; 248 TRACE_PORT(vPorts[port_id]); 249 c->pScHpfMode = vPorts[port_id++]; 250 TRACE_PORT(vPorts[port_id]); 251 c->pScHpfFreq = vPorts[port_id++]; 252 TRACE_PORT(vPorts[port_id]); 253 c->pScLpfMode = vPorts[port_id++]; 254 TRACE_PORT(vPorts[port_id]); 255 c->pScLpfFreq = vPorts[port_id++]; 256 } 257 } 258 259 // Compressor ports 260 lsp_trace("Binding compressor ports"); 261 for (size_t i=0; i<channels; ++i) 262 { 263 channel_t *c = &vChannels[i]; 264 265 if ((i > 0) && (nMode == CM_STEREO)) 266 { 267 channel_t *sc = &vChannels[0]; 268 269 c->pMode = sc->pMode; 270 c->pAttackLvl = sc->pAttackLvl; 271 c->pAttackTime = sc->pAttackTime; 272 c->pReleaseLvl = sc->pReleaseLvl; 273 c->pReleaseTime = sc->pReleaseTime; 274 c->pRatio = sc->pRatio; 275 c->pKnee = sc->pKnee; 276 c->pBThresh = sc->pBThresh; 277 c->pBoost = sc->pBoost; 278 c->pMakeup = sc->pMakeup; 279 c->pDryGain = sc->pDryGain; 280 c->pWetGain = sc->pWetGain; 281 } 282 else 283 { 284 TRACE_PORT(vPorts[port_id]); 285 c->pMode = vPorts[port_id++]; 286 TRACE_PORT(vPorts[port_id]); 287 c->pAttackLvl = vPorts[port_id++]; 288 TRACE_PORT(vPorts[port_id]); 289 c->pAttackTime = vPorts[port_id++]; 290 TRACE_PORT(vPorts[port_id]); 291 c->pReleaseLvl = vPorts[port_id++]; 292 TRACE_PORT(vPorts[port_id]); 293 c->pReleaseTime = vPorts[port_id++]; 294 TRACE_PORT(vPorts[port_id]); 295 c->pRatio = vPorts[port_id++]; 296 TRACE_PORT(vPorts[port_id]); 297 c->pKnee = vPorts[port_id++]; 298 TRACE_PORT(vPorts[port_id]); 299 c->pBThresh = vPorts[port_id++]; 300 TRACE_PORT(vPorts[port_id]); 301 c->pBoost = vPorts[port_id++]; 302 TRACE_PORT(vPorts[port_id]); 303 c->pMakeup = vPorts[port_id++]; 304 TRACE_PORT(vPorts[port_id]); 305 c->pDryGain = vPorts[port_id++]; 306 TRACE_PORT(vPorts[port_id]); 307 c->pWetGain = vPorts[port_id++]; 308 TRACE_PORT(vPorts[port_id]); 309 c->pReleaseOut = vPorts[port_id++]; 310 311 // Skip meters visibility controls 312 TRACE_PORT(vPorts[port_id]); 313 port_id++; 314 TRACE_PORT(vPorts[port_id]); 315 port_id++; 316 TRACE_PORT(vPorts[port_id]); 317 port_id++; 318 319 TRACE_PORT(vPorts[port_id]); 320 c->pCurve = vPorts[port_id++]; 321 TRACE_PORT(vPorts[port_id]); 322 c->pGraph[G_SC] = vPorts[port_id++]; 323 TRACE_PORT(vPorts[port_id]); 324 c->pGraph[G_ENV] = vPorts[port_id++]; 325 TRACE_PORT(vPorts[port_id]); 326 c->pGraph[G_GAIN] = vPorts[port_id++]; 327 TRACE_PORT(vPorts[port_id]); 328 c->pMeter[M_SC] = vPorts[port_id++]; 329 TRACE_PORT(vPorts[port_id]); 330 c->pMeter[M_CURVE] = vPorts[port_id++]; 331 TRACE_PORT(vPorts[port_id]); 332 c->pMeter[M_ENV] = vPorts[port_id++]; 333 TRACE_PORT(vPorts[port_id]); 334 c->pMeter[M_GAIN] = vPorts[port_id++]; 335 } 336 } 337 338 // Bind history 339 lsp_trace("Binding history ports"); 340 for (size_t i=0; i<channels; ++i) 341 { 342 channel_t *c = &vChannels[i]; 343 344 // Skip meters visibility controls 345 TRACE_PORT(vPorts[port_id]); 346 port_id++; 347 TRACE_PORT(vPorts[port_id]); 348 port_id++; 349 350 // Bind ports 351 TRACE_PORT(vPorts[port_id]); 352 c->pGraph[G_IN] = vPorts[port_id++]; 353 TRACE_PORT(vPorts[port_id]); 354 c->pGraph[G_OUT] = vPorts[port_id++]; 355 TRACE_PORT(vPorts[port_id]); 356 c->pMeter[M_IN] = vPorts[port_id++]; 357 TRACE_PORT(vPorts[port_id]); 358 c->pMeter[M_OUT] = vPorts[port_id++]; 359 } 360 361 // Initialize curve (logarithmic) in range of -72 .. +24 db 362 float delta = (compressor_base_metadata::CURVE_DB_MAX - compressor_base_metadata::CURVE_DB_MIN) / (compressor_base_metadata::CURVE_MESH_SIZE-1); 363 for (size_t i=0; i<compressor_base_metadata::CURVE_MESH_SIZE; ++i) 364 vCurve[i] = db_to_gain(compressor_base_metadata::CURVE_DB_MIN + delta * i); 365 366 // Initialize time points 367 delta = compressor_base_metadata::TIME_HISTORY_MAX / (compressor_base_metadata::TIME_MESH_SIZE - 1); 368 for (size_t i=0; i<compressor_base_metadata::TIME_MESH_SIZE; ++i) 369 vTime[i] = compressor_base_metadata::TIME_HISTORY_MAX - i*delta; 370 } 371 destroy()372 void compressor_base::destroy() 373 { 374 if (vChannels != NULL) 375 { 376 size_t channels = (nMode == CM_MONO) ? 1 : 2; 377 for (size_t i=0; i<channels; ++i) 378 { 379 vChannels[i].sSC.destroy(); 380 vChannels[i].sSCEq.destroy(); 381 vChannels[i].sDelay.destroy(); 382 vChannels[i].sCompDelay.destroy(); 383 vChannels[i].sDryDelay.destroy(); 384 } 385 386 delete [] vChannels; 387 vChannels = NULL; 388 } 389 390 if (pData != NULL) 391 { 392 delete [] pData; 393 pData = NULL; 394 } 395 396 if (pIDisplay != NULL) 397 { 398 pIDisplay->detroy(); 399 pIDisplay = NULL; 400 } 401 } 402 update_sample_rate(long sr)403 void compressor_base::update_sample_rate(long sr) 404 { 405 size_t samples_per_dot = seconds_to_samples(sr, compressor_base_metadata::TIME_HISTORY_MAX / compressor_base_metadata::TIME_MESH_SIZE); 406 size_t channels = (nMode == CM_MONO) ? 1 : 2; 407 size_t max_delay = millis_to_samples(fSampleRate, compressor_base_metadata::LOOKAHEAD_MAX); 408 409 for (size_t i=0; i<channels; ++i) 410 { 411 channel_t *c = &vChannels[i]; 412 c->sBypass.init(sr); 413 c->sComp.set_sample_rate(sr); 414 c->sSC.set_sample_rate(sr); 415 c->sSCEq.set_sample_rate(sr); 416 c->sDelay.init(max_delay); 417 c->sCompDelay.init(max_delay); 418 c->sDryDelay.init(max_delay); 419 420 for (size_t j=0; j<G_TOTAL; ++j) 421 c->sGraph[j].init(compressor_base_metadata::TIME_MESH_SIZE, samples_per_dot); 422 c->sGraph[G_GAIN].fill(1.0f); 423 } 424 } 425 decode_mode(int mode)426 compressor_mode_t compressor_base::decode_mode(int mode) 427 { 428 switch (mode) 429 { 430 case compressor_base_metadata::CM_DOWNWARD: return CM_DOWNWARD; 431 case compressor_base_metadata::CM_UPWARD: return CM_UPWARD; 432 case compressor_base_metadata::CM_BOOSTING: return CM_BOOSTING; 433 default: return CM_DOWNWARD; 434 } 435 } 436 update_settings()437 void compressor_base::update_settings() 438 { 439 filter_params_t fp; 440 size_t channels = (nMode == CM_MONO) ? 1 : 2; 441 bool bypass = pBypass->getValue() >= 0.5f; 442 443 // Global parameters 444 bPause = pPause->getValue() >= 0.5f; 445 bClear = pClear->getValue() >= 0.5f; 446 bMSListen = (pMSListen != NULL) ? pMSListen->getValue() >= 0.5f : false; 447 fInGain = pInGain->getValue(); 448 float out_gain = pOutGain->getValue(); 449 size_t latency = 0; 450 451 for (size_t i=0; i<channels; ++i) 452 { 453 channel_t *c = &vChannels[i]; 454 455 // Update bypass settings 456 c->sBypass.set_bypass(bypass); 457 458 // Update sidechain settings 459 c->nScType = c->pScType->getValue(); 460 c->bScListen = c->pScListen->getValue() >= 0.5f; 461 462 c->sSC.set_gain(c->pScPreamp->getValue()); 463 c->sSC.set_mode((c->pScMode != NULL) ? c->pScMode->getValue() : SCM_RMS); 464 c->sSC.set_source((c->pScSource != NULL) ? c->pScSource->getValue() : SCS_MIDDLE); 465 c->sSC.set_reactivity(c->pScReactivity->getValue()); 466 c->sSC.set_stereo_mode(((nMode == CM_MS) && (c->nScType != SCT_EXTERNAL)) ? SCSM_MIDSIDE : SCSM_STEREO); 467 468 // Setup hi-pass filter for sidechain 469 size_t hp_slope = c->pScHpfMode->getValue() * 2; 470 fp.nType = (hp_slope > 0) ? FLT_BT_BWC_HIPASS : FLT_NONE; 471 fp.fFreq = c->pScHpfFreq->getValue(); 472 fp.fFreq2 = fp.fFreq; 473 fp.fGain = 1.0f; 474 fp.nSlope = hp_slope; 475 fp.fQuality = 0.0f; 476 c->sSCEq.set_params(0, &fp); 477 478 // Setup low-pass filter for sidechain 479 size_t lp_slope = c->pScLpfMode->getValue() * 2; 480 fp.nType = (lp_slope > 0) ? FLT_BT_BWC_LOPASS : FLT_NONE; 481 fp.fFreq = c->pScLpfFreq->getValue(); 482 fp.fFreq2 = fp.fFreq; 483 fp.fGain = 1.0f; 484 fp.nSlope = lp_slope; 485 fp.fQuality = 0.0f; 486 c->sSCEq.set_params(1, &fp); 487 488 // Update delay and estimate overall delay 489 size_t delay = millis_to_samples(fSampleRate, (c->pScLookahead != NULL) ? c->pScLookahead->getValue() : 0); 490 c->sDelay.set_delay(delay); 491 if (delay > latency) 492 latency = delay; 493 494 // Update compressor settings 495 float attack = c->pAttackLvl->getValue(); 496 float release = c->pReleaseLvl->getValue() * attack; 497 float makeup = c->pMakeup->getValue(); 498 compressor_mode_t mode = decode_mode(c->pMode->getValue()); 499 500 c->sComp.set_threshold(attack, release); 501 c->sComp.set_timings(c->pAttackTime->getValue(), c->pReleaseTime->getValue()); 502 c->sComp.set_ratio(c->pRatio->getValue()); 503 c->sComp.set_knee(c->pKnee->getValue()); 504 c->sComp.set_boost_threshold((mode != CM_BOOSTING) ? c->pBThresh->getValue() : c->pBoost->getValue()); 505 c->sComp.set_mode(mode); 506 if (c->pReleaseOut != NULL) 507 c->pReleaseOut->setValue(release); 508 c->sGraph[G_GAIN].set_method((mode == CM_DOWNWARD) ? MM_MINIMUM : MM_MAXIMUM); 509 510 // Check modification flag 511 if (c->sComp.modified()) 512 { 513 c->sComp.update_settings(); 514 c->nSync |= S_CURVE; 515 } 516 517 // Update gains 518 c->fDryGain = c->pDryGain->getValue() * out_gain; 519 c->fWetGain = c->pWetGain->getValue() * out_gain; 520 if (c->fMakeup != makeup) 521 { 522 c->fMakeup = makeup; 523 c->nSync |= S_CURVE; 524 } 525 } 526 527 // Tune compensation delays 528 for (size_t i=0; i<channels; ++i) 529 { 530 channel_t *c = &vChannels[i]; 531 c->sCompDelay.set_delay(latency - c->sDelay.get_delay()); 532 c->sDryDelay.set_delay(latency); 533 } 534 535 // Report latency 536 set_latency(latency); 537 } 538 ui_activated()539 void compressor_base::ui_activated() 540 { 541 size_t channels = (nMode == CM_MONO) ? 1 : 2; 542 for (size_t i=0; i<channels; ++i) 543 vChannels[i].nSync = S_CURVE; 544 bUISync = true; 545 } 546 process_feedback(channel_t * c,size_t i,size_t channels)547 float compressor_base::process_feedback(channel_t *c, size_t i, size_t channels) 548 { 549 // Read input samples 550 float in[2]; 551 if (channels > 1) 552 { 553 in[0] = vChannels[0].fFeedback; 554 in[1] = vChannels[1].fFeedback; 555 } 556 else 557 { 558 in[0] = c->fFeedback; 559 in[1] = 0.0f; 560 } 561 562 // Process sidechain 563 float scin = c->sSC.process(in); 564 565 // Perform compression routine 566 c->vGain[i] = c->sComp.process(&c->vEnv[i], scin); 567 c->vOut[i] = c->vGain[i] * c->vIn[i]; 568 569 return scin; 570 } 571 process_non_feedback(channel_t * c,float ** in,size_t samples)572 void compressor_base::process_non_feedback(channel_t *c, float **in, size_t samples) 573 { 574 c->sSC.process(c->vSc, const_cast<const float **>(in), samples); 575 c->sComp.process(c->vGain, c->vEnv, c->vSc, samples); 576 dsp::mul3(c->vOut, c->vGain, c->vIn, samples); // Adjust gain for input 577 } 578 process(size_t samples)579 void compressor_base::process(size_t samples) 580 { 581 size_t channels = (nMode == CM_MONO) ? 1 : 2; 582 size_t feedback = 0; 583 584 float *in_buf[2]; // Input buffer 585 float *out_buf[2]; // Output buffer 586 float *sc_buf[2]; // Sidechain source 587 float *in[2]; // Buffet to pass to sidechain 588 589 // Prepare audio channels 590 for (size_t i=0; i<channels; ++i) 591 { 592 channel_t *c = &vChannels[i]; 593 594 // Initialize pointers 595 in_buf[i] = c->pIn->getBuffer<float>(); 596 out_buf[i] = c->pOut->getBuffer<float>(); 597 sc_buf[i] = (c->pSC != NULL) ? c->pSC->getBuffer<float>() : in_buf[i]; 598 599 // Analyze channel mode 600 if (c->nScType == SCT_FEED_BACK) 601 feedback |= (1 << i); 602 603 // lsp_dumpf("in_buf", "%g", in_buf[i], samples); 604 } 605 606 // Perform compression 607 size_t left = samples; 608 while (left > 0) 609 { 610 // Detemine number of samples to process 611 size_t to_process = (left > COMP_BUF_SIZE) ? COMP_BUF_SIZE : left; 612 613 // Prepare audio channels 614 if (nMode == CM_MONO) 615 dsp::mul_k3(vChannels[0].vIn, in_buf[0], fInGain, to_process); 616 else if (nMode == CM_MS) 617 { 618 dsp::lr_to_ms(vChannels[0].vIn, vChannels[1].vIn, in_buf[0], in_buf[1], to_process); 619 dsp::mul_k2(vChannels[0].vIn, fInGain, to_process); 620 dsp::mul_k2(vChannels[1].vIn, fInGain, to_process); 621 } 622 else 623 { 624 dsp::mul_k3(vChannels[0].vIn, in_buf[0], fInGain, to_process); 625 dsp::mul_k3(vChannels[1].vIn, in_buf[1], fInGain, to_process); 626 } 627 628 // Process meters 629 for (size_t i=0; i<channels; ++i) 630 { 631 channel_t *c = &vChannels[i]; 632 // Update input graph 633 c->sGraph[G_IN].process(c->vIn, to_process); 634 c->pMeter[M_IN]->setValue(dsp::abs_max(c->vIn, to_process)); 635 } 636 637 // Do compression 638 switch (feedback) 639 { 640 case 0: 641 { 642 if (channels > 1) // Process second channel in stereo pair 643 { 644 // First channel 645 in[0] = (vChannels[0].nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 646 in[1] = (vChannels[0].nScType == SCT_EXTERNAL) ? sc_buf[1] : vChannels[1].vIn; 647 process_non_feedback(&vChannels[0], in, to_process); 648 vChannels[0].fFeedback = vChannels[0].vOut[to_process-1]; 649 650 // Second channel 651 in[0] = (vChannels[1].nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 652 in[1] = (vChannels[1].nScType == SCT_EXTERNAL) ? sc_buf[1] : vChannels[1].vIn; 653 process_non_feedback(&vChannels[1], in, to_process); 654 vChannels[1].fFeedback = vChannels[1].vOut[to_process-1]; 655 } 656 else 657 { 658 // Only one channel 659 in[0] = (vChannels[0].nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 660 in[1] = NULL; 661 process_non_feedback(&vChannels[0], in, to_process); 662 vChannels[0].fFeedback = vChannels[0].vOut[to_process-1]; 663 } 664 665 break; 666 } 667 668 case 1: 669 { 670 // 0=FB [1=FF/EXT] 671 if (channels > 1) 672 { 673 // Second channel 674 in[0] = (vChannels[1].nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 675 in[1] = (vChannels[1].nScType == SCT_EXTERNAL) ? sc_buf[1] : vChannels[1].vIn; 676 process_non_feedback(&vChannels[1], in, to_process); 677 // vChannels[1].fFeedback = vChannels[1].vOut[to_process-1]; // do not update feedback at this time 678 679 // Process feedback channel 680 for (size_t i=0; i<to_process; ++i) 681 { 682 vChannels[0].vSc[i] = process_feedback(&vChannels[0], i, channels); 683 vChannels[0].fFeedback = vChannels[0].vOut[i]; 684 vChannels[1].fFeedback = vChannels[1].vOut[i]; 685 } 686 } 687 else 688 { 689 // Process feedback channel 690 for (size_t i=0; i<to_process; ++i) 691 { 692 vChannels[0].vSc[i] = process_feedback(&vChannels[0], i, channels); 693 vChannels[0].fFeedback = vChannels[0].vOut[i]; 694 } 695 } 696 697 break; 698 } 699 700 case 2: 701 { 702 // 0=FF/EXT 1=FB 703 // First channel 704 in[0] = (vChannels[0].nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 705 in[1] = (vChannels[0].nScType == SCT_EXTERNAL) ? sc_buf[1] : vChannels[1].vIn; 706 process_non_feedback(&vChannels[0], in, to_process); 707 // vChannels[0].fFeedback = vChannels[0].vOut[to_process-1]; // do not update feedback at this time 708 709 // Process feedback channel 710 for (size_t i=0; i<to_process; ++i) 711 { 712 vChannels[1].vSc[i] = process_feedback(&vChannels[1], i, channels); 713 vChannels[1].fFeedback = vChannels[1].vOut[i]; 714 vChannels[0].fFeedback = vChannels[0].vOut[i]; 715 } 716 717 break; 718 } 719 720 case 3: 721 { 722 // 0=FB, 1=FB 723 for (size_t i=0; i<to_process; ++i) 724 { 725 vChannels[0].vSc[i] = process_feedback(&vChannels[0], i, channels); 726 vChannels[1].vSc[i] = process_feedback(&vChannels[1], i, channels); 727 vChannels[0].fFeedback = vChannels[0].vOut[i]; 728 vChannels[1].fFeedback = vChannels[1].vOut[i]; 729 } 730 break; 731 } 732 default: 733 break; 734 } 735 736 // Apply gain to each channel and process meters 737 for (size_t i=0; i<channels; ++i) 738 { 739 channel_t *c = &vChannels[i]; 740 741 // Add delay to original signal and apply gain 742 c->sDelay.process(c->vOut, c->vIn, c->vGain, to_process); 743 744 // Apply latency compensation delay 745 c->sCompDelay.process(c->vOut, c->vOut, to_process); 746 747 // Process graph outputs 748 if ((i == 0) || (nMode != CM_STEREO)) 749 { 750 c->sGraph[G_SC].process(c->vSc, to_process); // Sidechain signal 751 c->pMeter[M_SC]->setValue(dsp::abs_max(c->vSc, to_process)); 752 753 c->sGraph[G_GAIN].process(c->vGain, to_process); // Gain reduction signal 754 c->pMeter[M_GAIN]->setValue(dsp::abs_max(c->vGain, to_process)); 755 756 c->sGraph[G_ENV].process(c->vEnv, to_process); // Envelope signal 757 c->pMeter[M_ENV]->setValue(dsp::abs_max(c->vEnv, to_process)); 758 } 759 } 760 761 // Form output signal 762 if (nMode == CM_MS) 763 { 764 channel_t *cm = &vChannels[0]; 765 channel_t *cs = &vChannels[1]; 766 767 dsp::mix2(cm->vOut, cm->vIn, cm->fMakeup * cm->fWetGain, cm->fDryGain, to_process); 768 dsp::mix2(cs->vOut, cs->vIn, cs->fMakeup * cs->fWetGain, cs->fDryGain, to_process); 769 770 cm->sGraph[G_OUT].process(cm->vOut, to_process); 771 cm->pMeter[M_OUT]->setValue(dsp::abs_max(cm->vOut, to_process)); 772 cs->sGraph[G_OUT].process(cs->vOut, to_process); 773 cs->pMeter[M_OUT]->setValue(dsp::abs_max(cs->vOut, to_process)); 774 775 if (!bMSListen) 776 dsp::ms_to_lr(cm->vOut, cs->vOut, cm->vOut, cs->vOut, to_process); 777 if (cm->bScListen) 778 dsp::copy(cm->vOut, cm->vSc, to_process); 779 if (cs->bScListen) 780 dsp::copy(cs->vOut, cs->vSc, to_process); 781 } 782 else 783 { 784 for (size_t i=0; i<channels; ++i) 785 { 786 // Mix dry/wet signal or copy sidechain signal 787 channel_t *c = &vChannels[i]; 788 if (c->bScListen) 789 dsp::copy(c->vOut, c->vSc, to_process); 790 else 791 dsp::mix2(c->vOut, c->vIn, c->fMakeup * c->fWetGain, c->fDryGain, to_process); 792 793 c->sGraph[G_OUT].process(c->vOut, to_process); // Output signal 794 c->pMeter[M_OUT]->setValue(dsp::abs_max(c->vOut, to_process)); 795 } 796 } 797 798 // Final metering 799 for (size_t i=0; i<channels; ++i) 800 { 801 // Apply bypass 802 channel_t *c = &vChannels[i]; 803 c->sDryDelay.process(c->vIn, in_buf[i], to_process); // Apply latency compensation 804 c->sBypass.process(out_buf[i], c->vIn, vChannels[i].vOut, to_process); 805 806 // dump_buffer("out_buf", out_buf[i], samples); 807 808 in_buf[i] += to_process; 809 out_buf[i] += to_process; 810 sc_buf[i] += to_process; 811 } 812 813 left -= to_process; 814 } 815 816 if ((!bPause) || (bClear) || (bUISync)) 817 { 818 // Process mesh requests 819 for (size_t i=0; i<channels; ++i) 820 { 821 // Get channel 822 channel_t *c = &vChannels[i]; 823 824 for (size_t j=0; j<G_TOTAL; ++j) 825 { 826 // Check that port is bound 827 if (c->pGraph[j] == NULL) 828 continue; 829 830 // Clear data if requested 831 if (bClear) 832 dsp::fill_zero(c->sGraph[j].data(), compressor_base_metadata::TIME_MESH_SIZE); 833 834 // Get mesh 835 mesh_t *mesh = c->pGraph[j]->getBuffer<mesh_t>(); 836 if ((mesh != NULL) && (mesh->isEmpty())) 837 { 838 // Fill mesh with new values 839 dsp::copy(mesh->pvData[0], vTime, compressor_base_metadata::TIME_MESH_SIZE); 840 dsp::copy(mesh->pvData[1], c->sGraph[j].data(), compressor_base_metadata::TIME_MESH_SIZE); 841 mesh->data(2, compressor_base_metadata::TIME_MESH_SIZE); 842 } 843 } // for j 844 } 845 846 bUISync = false; 847 } 848 849 // Output compressor curves for each channel 850 for (size_t i=0; i<channels; ++i) 851 { 852 channel_t *c = &vChannels[i]; 853 854 // Output compression curve 855 if (c->pCurve != NULL) 856 { 857 mesh_t *mesh = c->pCurve->getBuffer<mesh_t>(); 858 if ((c->nSync & S_CURVE) && (mesh != NULL) && (mesh->isEmpty())) 859 { 860 // Copy frequency points 861 dsp::copy(mesh->pvData[0], vCurve, compressor_base_metadata::CURVE_MESH_SIZE); 862 c->sComp.curve(mesh->pvData[1], vCurve, compressor_base_metadata::CURVE_MESH_SIZE); 863 if (c->fMakeup != 1.0f) 864 dsp::mul_k2(mesh->pvData[1], c->fMakeup, compressor_base_metadata::CURVE_MESH_SIZE); 865 866 // Mark mesh containing data 867 mesh->data(2, compressor_base_metadata::CURVE_MESH_SIZE); 868 c->nSync &= ~S_CURVE; 869 } 870 } 871 872 // Update meter 873 if ((c->pMeter[M_ENV] != NULL) && (c->pMeter[M_CURVE] != NULL)) 874 { 875 c->fDotIn = c->pMeter[M_ENV]->getValue(); 876 c->fDotOut = c->sComp.curve(c->fDotIn) * c->fMakeup; 877 c->pMeter[M_CURVE]->setValue(c->fDotOut); 878 } 879 } 880 881 // Request for redraw 882 if (pWrapper != NULL) 883 pWrapper->query_display_draw(); 884 } 885 inline_display(ICanvas * cv,size_t width,size_t height)886 bool compressor_base::inline_display(ICanvas *cv, size_t width, size_t height) 887 { 888 // Check proportions 889 if (height > width) 890 height = width; 891 892 // Init canvas 893 if (!cv->init(width, height)) 894 return false; 895 width = cv->width(); 896 height = cv->height(); 897 898 // Clear background 899 bool bypassing = vChannels[0].sBypass.bypassing(); 900 cv->set_color_rgb((bypassing) ? CV_DISABLED : CV_BACKGROUND); 901 cv->paint(); 902 903 float zx = 1.0f/GAIN_AMP_M_72_DB; 904 float zy = 1.0f/GAIN_AMP_M_72_DB; 905 float dx = width/(logf(GAIN_AMP_P_24_DB)-logf(GAIN_AMP_M_72_DB)); 906 float dy = height/(logf(GAIN_AMP_M_72_DB)-logf(GAIN_AMP_P_24_DB)); 907 908 // Draw horizontal and vertical lines 909 cv->set_line_width(1.0); 910 cv->set_color_rgb((bypassing) ? CV_SILVER: CV_YELLOW, 0.5f); 911 for (float i=GAIN_AMP_M_72_DB; i<GAIN_AMP_P_24_DB; i *= GAIN_AMP_P_24_DB) 912 { 913 float ax = dx*(logf(i*zx)); 914 float ay = height + dy*(logf(i*zy)); 915 cv->line(ax, 0, ax, height); 916 cv->line(0, ay, width, ay); 917 } 918 919 // Draw 1:1 line 920 cv->set_line_width(2.0); 921 cv->set_color_rgb(CV_GRAY); 922 { 923 float ax1 = dx*(logf(GAIN_AMP_M_72_DB*zx)); 924 float ax2 = dx*(logf(GAIN_AMP_P_24_DB*zx)); 925 float ay1 = height + dy*(logf(GAIN_AMP_M_72_DB*zy)); 926 float ay2 = height + dy*(logf(GAIN_AMP_P_24_DB*zy)); 927 cv->line(ax1, ay1, ax2, ay2); 928 } 929 930 // Draw axis 931 cv->set_color_rgb((bypassing) ? CV_SILVER : CV_WHITE); 932 { 933 float ax = dx*(logf(GAIN_AMP_0_DB*zx)); 934 float ay = height + dy*(logf(GAIN_AMP_0_DB*zy)); 935 cv->line(ax, 0, ax, height); 936 cv->line(0, ay, width, ay); 937 } 938 939 // Reuse display 940 pIDisplay = float_buffer_t::reuse(pIDisplay, 4, width); 941 float_buffer_t *b = pIDisplay; 942 if (b == NULL) 943 return false; 944 945 size_t channels = ((nMode == CM_MONO) || (nMode == CM_STEREO)) ? 1 : 2; 946 static uint32_t c_colors[] = { 947 CV_MIDDLE_CHANNEL, CV_MIDDLE_CHANNEL, 948 CV_MIDDLE_CHANNEL, CV_MIDDLE_CHANNEL, 949 CV_LEFT_CHANNEL, CV_RIGHT_CHANNEL, 950 CV_MIDDLE_CHANNEL, CV_SIDE_CHANNEL 951 }; 952 953 bool aa = cv->set_anti_aliasing(true); 954 cv->set_line_width(2); 955 956 for (size_t i=0; i<channels; ++i) 957 { 958 channel_t *c = &vChannels[i]; 959 960 for (size_t j=0; j<width; ++j) 961 { 962 size_t k = (j*compressor_base_metadata::CURVE_MESH_SIZE)/width; 963 b->v[0][j] = vCurve[k]; 964 } 965 c->sComp.curve(b->v[1], b->v[0], width); 966 if (c->fMakeup != 1.0f) 967 dsp::mul_k2(b->v[1], c->fMakeup, width); 968 969 dsp::fill(b->v[2], 0.0f, width); 970 dsp::fill(b->v[3], height, width); 971 dsp::axis_apply_log1(b->v[2], b->v[0], zx, dx, width); 972 dsp::axis_apply_log1(b->v[3], b->v[1], zy, dy, width); 973 974 // Draw mesh 975 uint32_t color = (bypassing || !(active())) ? CV_SILVER : c_colors[nMode*2 + i]; 976 cv->set_color_rgb(color); 977 cv->draw_lines(b->v[2], b->v[3], width); 978 } 979 980 // Draw dot 981 if (active()) 982 { 983 for (size_t i=0; i<channels; ++i) 984 { 985 channel_t *c = &vChannels[i]; 986 987 uint32_t color = (bypassing) ? CV_SILVER : c_colors[nMode*2 + i]; 988 Color c1(color), c2(color); 989 c2.alpha(0.9); 990 991 float ax = dx*(logf(c->fDotIn*zx)); 992 float ay = height + dy*(logf(c->fDotOut*zy)); 993 994 cv->radial_gradient(ax, ay, c1, c2, 12); 995 cv->set_color_rgb(0); 996 cv->circle(ax, ay, 4); 997 cv->set_color_rgb(color); 998 cv->circle(ax, ay, 3); 999 } 1000 } 1001 1002 cv->set_anti_aliasing(aa); 1003 1004 return true; 1005 } 1006 dump(IStateDumper * v) const1007 void compressor_base::dump(IStateDumper *v) const 1008 { 1009 plugin_t::dump(v); 1010 1011 size_t channels = (nMode == CM_MONO) ? 1 : 2; 1012 1013 v->write("nMode", nMode); 1014 v->write("nChannels", channels); 1015 v->write("bSidechain", bSidechain); 1016 1017 v->begin_array("vChannels", vChannels, channels); 1018 for (size_t i=0; i<channels; ++i) 1019 { 1020 const channel_t *c = &vChannels[i]; 1021 1022 v->begin_object(c, sizeof(channel_t)); 1023 { 1024 v->write_object("sBypass", &c->sBypass); 1025 v->write_object("sSC", &c->sSC); 1026 v->write_object("sSCEq", &c->sSCEq); 1027 v->write_object("sComp", &c->sComp); 1028 v->write_object("sDelay", &c->sDelay); 1029 v->write_object("sCompDelay", &c->sCompDelay); 1030 v->write_object("sDryDelay", &c->sDryDelay); 1031 1032 v->begin_array("sGraph", c->sGraph, G_TOTAL); 1033 for (size_t j=0; j<G_TOTAL; ++j) 1034 v->write_object(&c->sGraph[j]); 1035 v->end_array(); 1036 1037 v->write("vIn", c->vIn); 1038 v->write("vOut", c->vOut); 1039 v->write("vSc", c->vSc); 1040 v->write("vEnv", c->vEnv); 1041 v->write("vGain", c->vGain); 1042 v->write("bScListen", c->bScListen); 1043 v->write("nSync", c->nSync); 1044 v->write("nScType", c->nScType); 1045 v->write("fMakeup", c->fMakeup); 1046 v->write("fFeedback", c->fFeedback); 1047 v->write("fDryGain", c->fDryGain); 1048 v->write("fWetGain", c->fWetGain); 1049 v->write("fDotIn", c->fDotIn); 1050 v->write("fDotOut", c->fDotOut); 1051 1052 v->write("pIn", c->pIn); 1053 v->write("pOut", c->pOut); 1054 v->write("pSC", c->pSC); 1055 v->begin_array("pGraph", c->pGraph, G_TOTAL); 1056 for (size_t j=0; j<G_TOTAL; ++j) 1057 v->write(c->pGraph[j]); 1058 v->end_array(); 1059 v->begin_array("pMeter", c->pGraph, M_TOTAL); 1060 for (size_t j=0; j<M_TOTAL; ++j) 1061 v->write(c->pMeter[j]); 1062 v->end_array(); 1063 1064 v->write("pScType", c->pScType); 1065 v->write("pScMode", c->pScMode); 1066 v->write("pScLookahead", c->pScLookahead); 1067 v->write("pScListen", c->pScListen); 1068 v->write("pScSource", c->pScSource); 1069 v->write("pScReactivity", c->pScReactivity); 1070 v->write("pScPreamp", c->pScPreamp); 1071 v->write("pScHpfMode", c->pScHpfMode); 1072 v->write("pScHpfFreq", c->pScHpfFreq); 1073 v->write("pScLpfMode", c->pScLpfMode); 1074 v->write("pScLpfFreq", c->pScLpfFreq); 1075 1076 v->write("pMode", c->pMode); 1077 v->write("pAttackLvl", c->pAttackLvl); 1078 v->write("pReleaseLvl", c->pReleaseLvl); 1079 v->write("pAttackTime", c->pAttackTime); 1080 v->write("pReleaseTime", c->pReleaseTime); 1081 v->write("pRatio", c->pRatio); 1082 v->write("pKnee", c->pKnee); 1083 v->write("pBThresh", c->pBThresh); 1084 v->write("pBoost", c->pBoost); 1085 v->write("pMakeup", c->pMakeup); 1086 1087 v->write("pDryGain", c->pDryGain); 1088 v->write("pWetGain", c->pWetGain); 1089 v->write("pCurve", c->pCurve); 1090 v->write("pReleaseOut", c->pReleaseOut); 1091 } 1092 v->end_object(); 1093 } 1094 v->end_array(); 1095 1096 v->write("vCurve", vCurve); 1097 v->write("vTime", vTime); 1098 v->write("bPause", bPause); 1099 v->write("bClear", bClear); 1100 v->write("bMSListen", bMSListen); 1101 v->write("fInGain", fInGain); 1102 v->write("bUISync", bUISync); 1103 v->write("pIDisplay", pIDisplay); 1104 v->write("pBypass", pBypass); 1105 v->write("pInGain", pInGain); 1106 v->write("pOutGain", pOutGain); 1107 v->write("pPause", pPause); 1108 v->write("pClear", pClear); 1109 v->write("pMSListen", pMSListen); 1110 v->write("pData", pData); 1111 } 1112 1113 //------------------------------------------------------------------------- 1114 // Compressor derivatives compressor_mono()1115 compressor_mono::compressor_mono() : compressor_base(metadata, false, CM_MONO) 1116 { 1117 } 1118 compressor_stereo()1119 compressor_stereo::compressor_stereo() : compressor_base(metadata, false, CM_STEREO) 1120 { 1121 } 1122 compressor_lr()1123 compressor_lr::compressor_lr() : compressor_base(metadata, false, CM_LR) 1124 { 1125 } 1126 compressor_ms()1127 compressor_ms::compressor_ms() : compressor_base(metadata, false, CM_MS) 1128 { 1129 } 1130 sc_compressor_mono()1131 sc_compressor_mono::sc_compressor_mono() : compressor_base(metadata, true, CM_MONO) 1132 { 1133 } 1134 sc_compressor_stereo()1135 sc_compressor_stereo::sc_compressor_stereo() : compressor_base(metadata, true, CM_STEREO) 1136 { 1137 } 1138 sc_compressor_lr()1139 sc_compressor_lr::sc_compressor_lr() : compressor_base(metadata, true, CM_LR) 1140 { 1141 } 1142 sc_compressor_ms()1143 sc_compressor_ms::sc_compressor_ms() : compressor_base(metadata, true, CM_MS) 1144 { 1145 } 1146 } 1147 1148 1149