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: 7 нояб. 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/gate.h> 26 27 #define GATE_BUF_SIZE 0x1000 28 #define TRACE_PORT(p) lsp_trace(" port id=%s", (p)->metadata()->id); 29 30 namespace lsp 31 { 32 //------------------------------------------------------------------------- 33 // Gate base class 34 gate_base(const plugin_metadata_t & metadata,bool sc,size_t mode)35 gate_base::gate_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 ~gate_base()59 gate_base::~gate_base() 60 { 61 } 62 init(IWrapper * wrapper)63 void gate_base::init(IWrapper *wrapper) 64 { 65 plugin_t::init(wrapper); 66 size_t channels = (nMode == GM_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 = GATE_BUF_SIZE * sizeof(float); 75 size_t curve_size = (gate_base_metadata::CURVE_MESH_SIZE) * sizeof(float); 76 size_t history_size = (gate_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, gate_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_INTERNAL; 113 c->fMakeup = 1.0f; 114 c->fDryGain = 1.0f; 115 c->fWetGain = 0.0f; 116 c->fDotIn = 0.0f; 117 c->fDotOut = 0.0f; 118 119 c->pIn = NULL; 120 c->pOut = NULL; 121 c->pSC = NULL; 122 123 for (size_t j=0; j<G_TOTAL; ++j) 124 c->pGraph[j] = NULL; 125 126 for (size_t j=0; j<M_TOTAL; ++j) 127 c->pMeter[j] = NULL; 128 129 c->pScType = NULL; 130 c->pScMode = NULL; 131 c->pScLookahead = NULL; 132 c->pScListen = NULL; 133 c->pScSource = NULL; 134 c->pScReactivity = NULL; 135 c->pScPreamp = NULL; 136 c->pScHpfMode = NULL; 137 c->pScHpfFreq = NULL; 138 c->pScLpfMode = NULL; 139 c->pScLpfFreq = NULL; 140 141 c->pHyst = NULL; 142 c->pThresh[0] = NULL; 143 c->pThresh[1] = NULL; 144 c->pZone[0] = NULL; 145 c->pZone[1] = NULL; 146 c->pAttack = NULL; 147 c->pRelease = NULL; 148 c->pReduction = NULL; 149 c->pMakeup = NULL; 150 151 c->pDryGain = NULL; 152 c->pWetGain = NULL; 153 c->pCurve[0] = NULL; 154 c->pCurve[1] = NULL; 155 c->pZoneStart[0] = NULL; 156 c->pZoneStart[1] = NULL; 157 c->pHystStart = NULL; 158 } 159 160 lsp_assert(ptr < &pData[allocate]); 161 162 // Bind ports 163 size_t port_id = 0; 164 165 // Input ports 166 lsp_trace("Binding input ports"); 167 for (size_t i=0; i<channels; ++i) 168 { 169 TRACE_PORT(vPorts[port_id]); 170 vChannels[i].pIn = vPorts[port_id++]; 171 } 172 173 // Input ports 174 lsp_trace("Binding output ports"); 175 for (size_t i=0; i<channels; ++i) 176 { 177 TRACE_PORT(vPorts[port_id]); 178 vChannels[i].pOut = vPorts[port_id++]; 179 } 180 181 // Input ports 182 if (bSidechain) 183 { 184 lsp_trace("Binding sidechain ports"); 185 for (size_t i=0; i<channels; ++i) 186 { 187 TRACE_PORT(vPorts[port_id]); 188 vChannels[i].pSC = vPorts[port_id++]; 189 } 190 } 191 192 // Common ports 193 lsp_trace("Binding common ports"); 194 TRACE_PORT(vPorts[port_id]); 195 pBypass = vPorts[port_id++]; 196 TRACE_PORT(vPorts[port_id]); 197 pInGain = vPorts[port_id++]; 198 TRACE_PORT(vPorts[port_id]); 199 pOutGain = vPorts[port_id++]; 200 TRACE_PORT(vPorts[port_id]); 201 pPause = vPorts[port_id++]; 202 TRACE_PORT(vPorts[port_id]); 203 pClear = vPorts[port_id++]; 204 if (nMode == GM_MS) 205 { 206 TRACE_PORT(vPorts[port_id]); 207 pMSListen = vPorts[port_id++]; 208 } 209 210 // Sidechain ports 211 lsp_trace("Binding sidechain ports"); 212 for (size_t i=0; i<channels; ++i) 213 { 214 channel_t *c = &vChannels[i]; 215 216 if ((i > 0) && (nMode == GM_STEREO)) 217 { 218 channel_t *sc = &vChannels[0]; 219 c->pScType = sc->pScType; 220 c->pScSource = sc->pScSource; 221 c->pScMode = sc->pScMode; 222 c->pScLookahead = sc->pScLookahead; 223 c->pScListen = sc->pScListen; 224 c->pScReactivity = sc->pScReactivity; 225 c->pScPreamp = sc->pScPreamp; 226 c->pScHpfMode = sc->pScHpfMode; 227 c->pScHpfFreq = sc->pScHpfFreq; 228 c->pScLpfMode = sc->pScLpfMode; 229 c->pScLpfFreq = sc->pScLpfFreq; 230 } 231 else 232 { 233 if (bSidechain) 234 { 235 TRACE_PORT(vPorts[port_id]); 236 c->pScType = vPorts[port_id++]; 237 } 238 TRACE_PORT(vPorts[port_id]); 239 c->pScMode = vPorts[port_id++]; 240 TRACE_PORT(vPorts[port_id]); 241 c->pScLookahead = vPorts[port_id++]; 242 TRACE_PORT(vPorts[port_id]); 243 c->pScListen = vPorts[port_id++]; 244 if (nMode != GM_MONO) 245 { 246 TRACE_PORT(vPorts[port_id]); 247 c->pScSource = vPorts[port_id++]; 248 } 249 TRACE_PORT(vPorts[port_id]); 250 c->pScReactivity = vPorts[port_id++]; 251 TRACE_PORT(vPorts[port_id]); 252 c->pScPreamp = vPorts[port_id++]; 253 TRACE_PORT(vPorts[port_id]); 254 c->pScHpfMode = vPorts[port_id++]; 255 TRACE_PORT(vPorts[port_id]); 256 c->pScHpfFreq = vPorts[port_id++]; 257 TRACE_PORT(vPorts[port_id]); 258 c->pScLpfMode = vPorts[port_id++]; 259 TRACE_PORT(vPorts[port_id]); 260 c->pScLpfFreq = vPorts[port_id++]; 261 } 262 } 263 264 // Gate ports 265 lsp_trace("Binding gate ports"); 266 for (size_t i=0; i<channels; ++i) 267 { 268 channel_t *c = &vChannels[i]; 269 270 if ((i > 0) && (nMode == GM_STEREO)) 271 { 272 channel_t *sc = &vChannels[0]; 273 274 c->pHyst = sc->pHyst; 275 c->pThresh[0] = sc->pThresh[0]; 276 c->pThresh[1] = sc->pThresh[1]; 277 c->pZone[0] = sc->pZone[0]; 278 c->pZone[1] = sc->pZone[1]; 279 c->pAttack = sc->pAttack; 280 c->pRelease = sc->pRelease; 281 c->pReduction = sc->pReduction; 282 c->pMakeup = sc->pMakeup; 283 284 c->pDryGain = sc->pDryGain; 285 c->pWetGain = sc->pWetGain; 286 c->pZoneStart[0] = sc->pZoneStart[0]; 287 c->pZoneStart[1] = sc->pZoneStart[1]; 288 c->pHystStart = sc->pHystStart; 289 } 290 else 291 { 292 TRACE_PORT(vPorts[port_id]); 293 c->pHyst = vPorts[port_id++]; 294 TRACE_PORT(vPorts[port_id]); 295 c->pThresh[0] = vPorts[port_id++]; 296 TRACE_PORT(vPorts[port_id]); 297 c->pZone[0] = vPorts[port_id++]; 298 TRACE_PORT(vPorts[port_id]); 299 c->pThresh[1] = vPorts[port_id++]; 300 TRACE_PORT(vPorts[port_id]); 301 c->pZone[1] = vPorts[port_id++]; 302 TRACE_PORT(vPorts[port_id]); 303 c->pAttack = vPorts[port_id++]; 304 TRACE_PORT(vPorts[port_id]); 305 c->pRelease = vPorts[port_id++]; 306 TRACE_PORT(vPorts[port_id]); 307 c->pReduction = vPorts[port_id++]; 308 TRACE_PORT(vPorts[port_id]); 309 c->pMakeup = vPorts[port_id++]; 310 311 TRACE_PORT(vPorts[port_id]); 312 c->pDryGain = vPorts[port_id++]; 313 TRACE_PORT(vPorts[port_id]); 314 c->pWetGain = vPorts[port_id++]; 315 316 // Skip meters visibility controls 317 TRACE_PORT(vPorts[port_id]); 318 port_id++; 319 TRACE_PORT(vPorts[port_id]); 320 port_id++; 321 TRACE_PORT(vPorts[port_id]); 322 port_id++; 323 324 TRACE_PORT(vPorts[port_id]); 325 c->pZoneStart[0] = vPorts[port_id++]; 326 TRACE_PORT(vPorts[port_id]); 327 c->pHystStart = vPorts[port_id++]; 328 TRACE_PORT(vPorts[port_id]); 329 c->pZoneStart[1] = vPorts[port_id++]; 330 331 TRACE_PORT(vPorts[port_id]); 332 c->pCurve[0] = vPorts[port_id++]; 333 TRACE_PORT(vPorts[port_id]); 334 c->pCurve[1] = vPorts[port_id++]; 335 TRACE_PORT(vPorts[port_id]); 336 c->pGraph[G_SC] = vPorts[port_id++]; 337 TRACE_PORT(vPorts[port_id]); 338 c->pGraph[G_ENV] = vPorts[port_id++]; 339 TRACE_PORT(vPorts[port_id]); 340 c->pGraph[G_GAIN] = vPorts[port_id++]; 341 TRACE_PORT(vPorts[port_id]); 342 c->pMeter[M_SC] = vPorts[port_id++]; 343 TRACE_PORT(vPorts[port_id]); 344 c->pMeter[M_CURVE] = vPorts[port_id++]; 345 TRACE_PORT(vPorts[port_id]); 346 c->pMeter[M_ENV] = vPorts[port_id++]; 347 TRACE_PORT(vPorts[port_id]); 348 c->pMeter[M_GAIN] = vPorts[port_id++]; 349 } 350 } 351 352 // Bind history 353 lsp_trace("Binding history ports"); 354 for (size_t i=0; i<channels; ++i) 355 { 356 channel_t *c = &vChannels[i]; 357 358 // Skip meters visibility controls 359 TRACE_PORT(vPorts[port_id]); 360 port_id++; 361 TRACE_PORT(vPorts[port_id]); 362 port_id++; 363 364 // Bind ports 365 TRACE_PORT(vPorts[port_id]); 366 c->pGraph[G_IN] = vPorts[port_id++]; 367 TRACE_PORT(vPorts[port_id]); 368 c->pGraph[G_OUT] = vPorts[port_id++]; 369 TRACE_PORT(vPorts[port_id]); 370 c->pMeter[M_IN] = vPorts[port_id++]; 371 TRACE_PORT(vPorts[port_id]); 372 c->pMeter[M_OUT] = vPorts[port_id++]; 373 } 374 375 // Initialize curve (logarithmic) in range of -72 .. +24 db 376 float delta = (gate_base_metadata::CURVE_DB_MAX - gate_base_metadata::CURVE_DB_MIN) / (gate_base_metadata::CURVE_MESH_SIZE-1); 377 for (size_t i=0; i<gate_base_metadata::CURVE_MESH_SIZE; ++i) 378 vCurve[i] = db_to_gain(gate_base_metadata::CURVE_DB_MIN + delta * i); 379 380 // Initialize time points 381 delta = gate_base_metadata::TIME_HISTORY_MAX / (gate_base_metadata::TIME_MESH_SIZE - 1); 382 for (size_t i=0; i<gate_base_metadata::TIME_MESH_SIZE; ++i) 383 vTime[i] = gate_base_metadata::TIME_HISTORY_MAX - i*delta; 384 } 385 destroy()386 void gate_base::destroy() 387 { 388 if (vChannels != NULL) 389 { 390 size_t channels = (nMode == GM_MONO) ? 1 : 2; 391 for (size_t i=0; i<channels; ++i) 392 { 393 vChannels[i].sSC.destroy(); 394 vChannels[i].sSCEq.destroy(); 395 vChannels[i].sDelay.destroy(); 396 vChannels[i].sCompDelay.destroy(); 397 vChannels[i].sDryDelay.destroy(); 398 } 399 400 delete [] vChannels; 401 vChannels = NULL; 402 } 403 404 if (pData != NULL) 405 { 406 delete [] pData; 407 pData = NULL; 408 } 409 410 if (pIDisplay != NULL) 411 { 412 pIDisplay->detroy(); 413 pIDisplay = NULL; 414 } 415 } 416 update_sample_rate(long sr)417 void gate_base::update_sample_rate(long sr) 418 { 419 size_t samples_per_dot = seconds_to_samples(sr, gate_base_metadata::TIME_HISTORY_MAX / gate_base_metadata::TIME_MESH_SIZE); 420 size_t channels = (nMode == GM_MONO) ? 1 : 2; 421 size_t max_delay = millis_to_samples(fSampleRate, compressor_base_metadata::LOOKAHEAD_MAX); 422 423 for (size_t i=0; i<channels; ++i) 424 { 425 channel_t *c = &vChannels[i]; 426 c->sBypass.init(sr); 427 c->sGate.set_sample_rate(sr); 428 c->sSC.set_sample_rate(sr); 429 c->sSCEq.set_sample_rate(sr); 430 c->sDelay.init(max_delay); 431 c->sCompDelay.init(max_delay); 432 c->sDryDelay.init(max_delay); 433 434 for (size_t j=0; j<G_TOTAL; ++j) 435 c->sGraph[j].init(gate_base_metadata::TIME_MESH_SIZE, samples_per_dot); 436 437 c->sGraph[G_GAIN].fill(gate_base_metadata::REDUCTION_DFL); 438 c->sGraph[G_GAIN].set_method(MM_MINIMUM); 439 } 440 } 441 update_settings()442 void gate_base::update_settings() 443 { 444 filter_params_t fp; 445 size_t channels = (nMode == GM_MONO) ? 1 : 2; 446 bool bypass = pBypass->getValue() >= 0.5f; 447 448 // Global parameters 449 bPause = pPause->getValue() >= 0.5f; 450 bClear = pClear->getValue() >= 0.5f; 451 bMSListen = (pMSListen != NULL) ? pMSListen->getValue() >= 0.5f : false; 452 fInGain = pInGain->getValue(); 453 float out_gain = pOutGain->getValue(); 454 size_t latency = 0; 455 456 for (size_t i=0; i<channels; ++i) 457 { 458 channel_t *c = &vChannels[i]; 459 460 // Update bypass settings 461 c->sBypass.set_bypass(bypass); 462 463 // Update sidechain settings 464 c->nScType = (c->pScType != NULL) ? c->pScType->getValue() : SCT_INTERNAL; 465 c->bScListen = c->pScListen->getValue() >= 0.5f; 466 467 c->sSC.set_gain(c->pScPreamp->getValue()); 468 c->sSC.set_mode((c->pScMode != NULL) ? c->pScMode->getValue() : SCM_RMS); 469 c->sSC.set_source((c->pScSource != NULL) ? c->pScSource->getValue() : SCS_MIDDLE); 470 c->sSC.set_reactivity(c->pScReactivity->getValue()); 471 c->sSC.set_stereo_mode(((nMode == GM_MS) && (c->nScType != SCT_EXTERNAL)) ? SCSM_MIDSIDE : SCSM_STEREO); 472 473 // Setup hi-pass filter for sidechain 474 size_t hp_slope = c->pScHpfMode->getValue() * 2; 475 fp.nType = (hp_slope > 0) ? FLT_BT_BWC_HIPASS : FLT_NONE; 476 fp.fFreq = c->pScHpfFreq->getValue(); 477 fp.fFreq2 = fp.fFreq; 478 fp.fGain = 1.0f; 479 fp.nSlope = hp_slope; 480 fp.fQuality = 0.0f; 481 c->sSCEq.set_params(0, &fp); 482 483 // Setup low-pass filter for sidechain 484 size_t lp_slope = c->pScLpfMode->getValue() * 2; 485 fp.nType = (lp_slope > 0) ? FLT_BT_BWC_LOPASS : FLT_NONE; 486 fp.fFreq = c->pScLpfFreq->getValue(); 487 fp.fFreq2 = fp.fFreq; 488 fp.fGain = 1.0f; 489 fp.nSlope = lp_slope; 490 fp.fQuality = 0.0f; 491 c->sSCEq.set_params(1, &fp); 492 493 // Update delay 494 size_t delay = millis_to_samples(fSampleRate, (c->pScLookahead != NULL) ? c->pScLookahead->getValue() : 0); 495 c->sDelay.set_delay(delay); 496 if (delay > latency) 497 latency = delay; 498 499 // Update Gate settings 500 bool hyst = (c->pHyst != NULL) ? (c->pHyst->getValue() >= 0.5f) : false; 501 float thresh = c->pThresh[0]->getValue(); 502 float hthresh = (hyst) ? (thresh * c->pThresh[1]->getValue()) : thresh; 503 float zone = c->pZone[0]->getValue(); 504 float hzone = (hyst) ? (c->pZone[1]->getValue()) : zone; 505 float makeup = c->pMakeup->getValue(); 506 507 c->sGate.set_threshold(thresh, hthresh); 508 c->sGate.set_zone(zone, hzone); 509 c->sGate.set_timings(c->pAttack->getValue(), c->pRelease->getValue()); 510 c->sGate.set_reduction(c->pReduction->getValue()); 511 512 if (c->pZoneStart[0] != NULL) 513 c->pZoneStart[0]->setValue(thresh * zone); 514 if (c->pZoneStart[1] != NULL) 515 c->pZoneStart[1]->setValue(hthresh * hzone); 516 if (c->pHystStart != NULL) 517 c->pHystStart->setValue(hthresh); 518 519 // Check modification flag 520 if (c->sGate.modified()) 521 { 522 c->sGate.update_settings(); 523 c->nSync |= S_ALL; 524 } 525 526 // Update gains 527 c->fDryGain = c->pDryGain->getValue() * out_gain; 528 c->fWetGain = c->pWetGain->getValue() * out_gain; 529 if (c->fMakeup != makeup) 530 { 531 c->fMakeup = makeup; 532 c->nSync |= S_ALL; 533 } 534 } 535 536 // Tune compensation delays 537 for (size_t i=0; i<channels; ++i) 538 { 539 channel_t *c = &vChannels[i]; 540 c->sCompDelay.set_delay(latency - c->sDelay.get_delay()); 541 c->sDryDelay.set_delay(latency); 542 } 543 544 // Report latency 545 set_latency(latency); 546 } 547 ui_activated()548 void gate_base::ui_activated() 549 { 550 size_t channels = (nMode == GM_MONO) ? 1 : 2; 551 for (size_t i=0; i<channels; ++i) 552 vChannels[i].nSync = S_ALL; 553 bUISync = true; 554 } 555 process(size_t samples)556 void gate_base::process(size_t samples) 557 { 558 size_t channels = (nMode == GM_MONO) ? 1 : 2; 559 560 float *in_buf[2]; // Input buffer 561 float *out_buf[2]; // Output buffer 562 float *sc_buf[2]; // Sidechain source 563 const float *in[2]; // Buffet to pass to sidechain 564 565 // Prepare audio channels 566 for (size_t i=0; i<channels; ++i) 567 { 568 channel_t *c = &vChannels[i]; 569 570 // Initialize pointers 571 in_buf[i] = c->pIn->getBuffer<float>(); 572 out_buf[i] = c->pOut->getBuffer<float>(); 573 sc_buf[i] = (c->pSC != NULL) ? c->pSC->getBuffer<float>() : in_buf[i]; 574 c->fDotIn = 0.0f; 575 c->fDotOut = 0.0f; 576 } 577 578 // Perform gating 579 size_t left = samples; 580 while (left > 0) 581 { 582 // Detemine number of samples to process 583 size_t to_process = (left > GATE_BUF_SIZE) ? GATE_BUF_SIZE : left; 584 585 // Prepare audio channels 586 if (nMode == GM_MONO) 587 dsp::mul_k3(vChannels[0].vIn, in_buf[0], fInGain, to_process); 588 else if (nMode == GM_MS) 589 { 590 dsp::lr_to_ms(vChannels[0].vIn, vChannels[1].vIn, in_buf[0], in_buf[1], to_process); 591 dsp::mul_k2(vChannels[0].vIn, fInGain, to_process); 592 dsp::mul_k2(vChannels[1].vIn, fInGain, to_process); 593 } 594 else 595 { 596 dsp::mul_k3(vChannels[0].vIn, in_buf[0], fInGain, to_process); 597 dsp::mul_k3(vChannels[1].vIn, in_buf[1], fInGain, to_process); 598 } 599 600 // Perform sidechain processing for each channel 601 for (size_t i=0; i<channels; ++i) 602 { 603 channel_t *c = &vChannels[i]; 604 605 // Update input graph 606 c->sGraph[G_IN].process(c->vIn, to_process); 607 c->pMeter[M_IN]->setValue(dsp::abs_max(c->vIn, to_process)); 608 609 // Do gating 610 in[0] = (c->nScType == SCT_EXTERNAL) ? sc_buf[0] : vChannels[0].vIn; 611 if (channels > 1) 612 in[1] = (c->nScType == SCT_EXTERNAL) ? sc_buf[1] : vChannels[1].vIn; 613 c->sSC.process(c->vSc, in, to_process); 614 c->sGate.process(c->vGain, c->vEnv, c->vSc, to_process); 615 616 // Update gating dot 617 size_t idx = dsp::max_index(c->vEnv, to_process); 618 if (c->vEnv[idx] > c->fDotIn) 619 { 620 c->fDotIn = c->vEnv[idx]; 621 c->fDotOut = c->vGain[idx] * c->fDotIn * c->fMakeup; 622 } 623 } 624 625 // Apply gain to each channel 626 for (size_t i=0; i<channels; ++i) 627 { 628 channel_t *c = &vChannels[i]; 629 630 // Add delay to original signal and apply gain 631 c->sDelay.process(c->vOut, c->vIn, c->vGain, to_process); 632 633 // Apply latency compensation delay 634 c->sCompDelay.process(c->vOut, c->vOut, to_process); 635 636 // Process graph outputs 637 if ((i == 0) || (nMode != GM_STEREO)) 638 { 639 c->sGraph[G_SC].process(c->vSc, to_process); // Sidechain signal 640 c->pMeter[M_SC]->setValue(dsp::abs_max(c->vSc, to_process)); 641 642 c->sGraph[G_GAIN].process(c->vGain, to_process); // Gain reduction signal 643 c->pMeter[M_GAIN]->setValue(dsp::abs_max(c->vGain, to_process)); 644 645 c->sGraph[G_ENV].process(c->vEnv, to_process); // Envelope signal 646 c->pMeter[M_ENV]->setValue(dsp::abs_max(c->vEnv, to_process)); 647 } 648 } 649 650 // Form output signal 651 if (nMode == GM_MS) 652 { 653 channel_t *cm = &vChannels[0]; 654 channel_t *cs = &vChannels[1]; 655 656 dsp::mix2(cm->vOut, cm->vIn, cm->fMakeup * cm->fWetGain, cm->fDryGain, to_process); 657 dsp::mix2(cs->vOut, cs->vIn, cs->fMakeup * cs->fWetGain, cs->fDryGain, to_process); 658 659 cm->sGraph[G_OUT].process(cm->vOut, to_process); 660 cm->pMeter[M_OUT]->setValue(dsp::abs_max(cm->vOut, to_process)); 661 cs->sGraph[G_OUT].process(cs->vOut, to_process); 662 cs->pMeter[M_OUT]->setValue(dsp::abs_max(cs->vOut, to_process)); 663 664 if (!bMSListen) 665 dsp::ms_to_lr(cm->vOut, cs->vOut, cm->vOut, cs->vOut, to_process); 666 if (cm->bScListen) 667 dsp::copy(cm->vOut, cm->vSc, to_process); 668 if (cs->bScListen) 669 dsp::copy(cs->vOut, cs->vSc, to_process); 670 } 671 else 672 { 673 for (size_t i=0; i<channels; ++i) 674 { 675 // Mix dry/wet signal or copy sidechain signal 676 channel_t *c = &vChannels[i]; 677 if (c->bScListen) 678 dsp::copy(c->vOut, c->vSc, to_process); 679 else 680 dsp::mix2(c->vOut, c->vIn, c->fMakeup * c->fWetGain, c->fDryGain, to_process); 681 682 c->sGraph[G_OUT].process(c->vOut, to_process); // Output signal 683 c->pMeter[M_OUT]->setValue(dsp::abs_max(c->vOut, to_process)); 684 } 685 } 686 687 // Final metering 688 for (size_t i=0; i<channels; ++i) 689 { 690 // Apply bypass 691 channel_t *c = &vChannels[i]; 692 c->sDryDelay.process(c->vIn, in_buf[i], to_process); 693 c->sBypass.process(out_buf[i], c->vIn, c->vOut, to_process); 694 695 in_buf[i] += to_process; 696 out_buf[i] += to_process; 697 sc_buf[i] += to_process; 698 } 699 700 left -= to_process; 701 } 702 703 if ((!bPause) || (bClear) || (bUISync)) 704 { 705 // Process mesh requests 706 for (size_t i=0; i<channels; ++i) 707 { 708 // Get channel 709 channel_t *c = &vChannels[i]; 710 711 for (size_t j=0; j<G_TOTAL; ++j) 712 { 713 // Check that port is bound 714 if (c->pGraph[j] == NULL) 715 continue; 716 717 // Clear data if requested 718 if (bClear) 719 dsp::fill_zero(c->sGraph[j].data(), gate_base_metadata::TIME_MESH_SIZE); 720 721 // Get mesh 722 mesh_t *mesh = c->pGraph[j]->getBuffer<mesh_t>(); 723 if ((mesh != NULL) && (mesh->isEmpty())) 724 { 725 // Fill mesh with new values 726 dsp::copy(mesh->pvData[0], vTime, gate_base_metadata::TIME_MESH_SIZE); 727 dsp::copy(mesh->pvData[1], c->sGraph[j].data(), gate_base_metadata::TIME_MESH_SIZE); 728 mesh->data(2, gate_base_metadata::TIME_MESH_SIZE); 729 } 730 } // for j 731 } 732 bUISync = false; 733 } 734 735 // Output gate curves for each channel 736 for (size_t i=0; i<channels; ++i) 737 { 738 channel_t *c = &vChannels[i]; 739 740 // Output gate curves 741 for (size_t j=0; j<2; ++j) 742 { 743 if (c->pCurve[j] == NULL) 744 continue; 745 746 mesh_t *mesh = c->pCurve[j]->getBuffer<mesh_t>(); 747 if ((c->nSync & (S_CURVE << j)) && (mesh != NULL) && (mesh->isEmpty())) 748 { 749 // Copy frequency points 750 dsp::copy(mesh->pvData[0], vCurve, gate_base_metadata::CURVE_MESH_SIZE); 751 c->sGate.curve(mesh->pvData[1], vCurve, gate_base_metadata::CURVE_MESH_SIZE, j > 0); 752 if (c->fMakeup != 1.0f) 753 dsp::mul_k2(mesh->pvData[1], c->fMakeup, gate_base_metadata::CURVE_MESH_SIZE); 754 755 // Mark mesh containing data 756 mesh->data(2, gate_base_metadata::CURVE_MESH_SIZE); 757 c->nSync &= ~(S_CURVE << j); 758 } 759 } 760 761 // Update meter 762 if ((c->pMeter[M_ENV] != NULL) && (c->pMeter[M_CURVE] != NULL)) 763 { 764 c->pMeter[M_ENV]->setValue(c->fDotIn); 765 c->pMeter[M_CURVE]->setValue(c->fDotOut); 766 } 767 } 768 769 // Request for redraw 770 if (pWrapper != NULL) 771 pWrapper->query_display_draw(); 772 } 773 inline_display(ICanvas * cv,size_t width,size_t height)774 bool gate_base::inline_display(ICanvas *cv, size_t width, size_t height) 775 { 776 // Check proportions 777 if (height > width) 778 height = width; 779 780 // Init canvas 781 if (!cv->init(width, height)) 782 return false; 783 width = cv->width(); 784 height = cv->height(); 785 786 // Clear background 787 bool bypassing = vChannels[0].sBypass.bypassing(); 788 cv->set_color_rgb((bypassing) ? CV_DISABLED : CV_BACKGROUND); 789 cv->paint(); 790 791 float zx = 1.0f/GAIN_AMP_M_72_DB; 792 float zy = 1.0f/GAIN_AMP_M_72_DB; 793 float dx = width/(logf(GAIN_AMP_P_24_DB)-logf(GAIN_AMP_M_72_DB)); 794 float dy = height/(logf(GAIN_AMP_M_72_DB)-logf(GAIN_AMP_P_24_DB)); 795 796 // Draw horizontal and vertical lines 797 cv->set_line_width(1.0); 798 cv->set_color_rgb((bypassing) ? CV_SILVER: CV_YELLOW, 0.5f); 799 for (float i=GAIN_AMP_M_72_DB; i<GAIN_AMP_P_24_DB; i *= GAIN_AMP_P_24_DB) 800 { 801 float ax = dx*(logf(i*zx)); 802 float ay = height + dy*(logf(i*zy)); 803 cv->line(ax, 0, ax, height); 804 cv->line(0, ay, width, ay); 805 } 806 807 // Draw 1:1 line 808 cv->set_line_width(2.0); 809 cv->set_color_rgb(CV_GRAY); 810 { 811 float ax1 = dx*(logf(GAIN_AMP_M_72_DB*zx)); 812 float ax2 = dx*(logf(GAIN_AMP_P_24_DB*zx)); 813 float ay1 = height + dy*(logf(GAIN_AMP_M_72_DB*zy)); 814 float ay2 = height + dy*(logf(GAIN_AMP_P_24_DB*zy)); 815 cv->line(ax1, ay1, ax2, ay2); 816 } 817 818 // Draw axis 819 cv->set_color_rgb((bypassing) ? CV_SILVER : CV_WHITE); 820 { 821 float ax = dx*(logf(GAIN_AMP_0_DB*zx)); 822 float ay = height + dy*(logf(GAIN_AMP_0_DB*zy)); 823 cv->line(ax, 0, ax, height); 824 cv->line(0, ay, width, ay); 825 } 826 827 // Reuse display 828 pIDisplay = float_buffer_t::reuse(pIDisplay, 4, width); 829 float_buffer_t *b = pIDisplay; 830 if (b == NULL) 831 return false; 832 833 size_t channels = ((nMode == GM_MONO) || (nMode == GM_STEREO)) ? 1 : 2; 834 static uint32_t c_colors[] = { 835 CV_MIDDLE_CHANNEL, CV_MIDDLE_CHANNEL, 836 CV_MIDDLE_CHANNEL, CV_MIDDLE_CHANNEL, 837 CV_LEFT_CHANNEL, CV_RIGHT_CHANNEL, 838 CV_MIDDLE_CHANNEL, CV_SIDE_CHANNEL 839 }; 840 841 bool aa = cv->set_anti_aliasing(true); 842 cv->set_line_width(2); 843 844 for (size_t i=0; i<channels; ++i) 845 { 846 channel_t *c = &vChannels[i]; 847 848 for (size_t j=0; j<2; ++j) 849 { 850 for (size_t k=0; k<width; ++k) 851 { 852 size_t n = (k*gate_base_metadata::CURVE_MESH_SIZE)/width; 853 b->v[0][k] = vCurve[n]; 854 } 855 c->sGate.curve(b->v[1], b->v[0], width, j > 0); 856 if (c->fMakeup != 1.0f) 857 dsp::mul_k2(b->v[1], c->fMakeup, width); 858 859 dsp::fill(b->v[2], 0.0f, width); 860 dsp::fill(b->v[3], height, width); 861 dsp::axis_apply_log1(b->v[2], b->v[0], zx, dx, width); 862 dsp::axis_apply_log1(b->v[3], b->v[1], zy, dy, width); 863 864 // Draw mesh 865 uint32_t color = (bypassing || !(active())) ? CV_SILVER : c_colors[nMode*2 + i]; 866 cv->set_color_rgb(color); 867 cv->draw_lines(b->v[2], b->v[3], width); 868 } 869 } 870 871 // Draw dot 872 if (active()) 873 { 874 for (size_t i=0; i<channels; ++i) 875 { 876 channel_t *c = &vChannels[i]; 877 878 uint32_t color = (bypassing) ? CV_SILVER : c_colors[nMode*2 + i]; 879 Color c1(color), c2(color); 880 c2.alpha(0.9); 881 882 float ax = dx*(logf(c->fDotIn*zx)); 883 float ay = height + dy*(logf(c->fDotOut*zy)); 884 885 cv->radial_gradient(ax, ay, c1, c2, 12); 886 cv->set_color_rgb(0); 887 cv->circle(ax, ay, 4); 888 cv->set_color_rgb(color); 889 cv->circle(ax, ay, 3); 890 } 891 } 892 893 cv->set_anti_aliasing(aa); 894 895 return true; 896 } 897 898 //------------------------------------------------------------------------- 899 // Gate derivatives gate_mono()900 gate_mono::gate_mono() : gate_base(metadata, false, GM_MONO) 901 { 902 } 903 gate_stereo()904 gate_stereo::gate_stereo() : gate_base(metadata, false, GM_STEREO) 905 { 906 } 907 gate_lr()908 gate_lr::gate_lr() : gate_base(metadata, false, GM_LR) 909 { 910 } 911 gate_ms()912 gate_ms::gate_ms() : gate_base(metadata, false, GM_MS) 913 { 914 } 915 sc_gate_mono()916 sc_gate_mono::sc_gate_mono() : gate_base(metadata, true, GM_MONO) 917 { 918 } 919 sc_gate_stereo()920 sc_gate_stereo::sc_gate_stereo() : gate_base(metadata, true, GM_STEREO) 921 { 922 } 923 sc_gate_lr()924 sc_gate_lr::sc_gate_lr() : gate_base(metadata, true, GM_LR) 925 { 926 } 927 sc_gate_ms()928 sc_gate_ms::sc_gate_ms() : gate_base(metadata, true, GM_MS) 929 { 930 } 931 } 932 933 934 935