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