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