1 /* darc.lv2
2 *
3 * Copyright (C) 2018,2019 Robin Gareus <robin@gareus.org>
4 * inspired by Fons Adriaensen's zita-dc1
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE
22 #endif
23
24 #include <math.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "darc.h"
31
32 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
33
34 #ifdef DISPLAY_INTERFACE
35 #include "lv2_rgext.h"
36 #include <cairo/cairo.h>
37 #include <pango/pangocairo.h>
38 #endif
39
40 #ifndef MAX
41 #define MAX(A, B) ((A) > (B)) ? (A) : (B)
42 #endif
43
44 #ifndef MIN
45 #define MIN(A, B) ((A) < (B)) ? (A) : (B)
46 #endif
47
48 /* ****************************************************************************/
49
50 typedef struct {
51 float sample_rate;
52
53 uint32_t n_channels;
54 float norm_input;
55
56 float ratio;
57 float p_rat;
58
59 bool hold;
60
61 float igain;
62 float p_ign;
63 float l_ign;
64
65 float p_thr;
66 float l_thr;
67
68 float w_att;
69 float w_rel;
70 float t_att;
71 float t_rel;
72
73 float za1;
74 float zr1;
75 float zr2;
76
77 bool newg;
78 float gmax;
79 float gmin;
80
81 float rms;
82 float w_rms;
83 float w_lpf;
84
85 } Dyncomp;
86
87 static inline void
Dyncomp_reset(Dyncomp * self)88 Dyncomp_reset (Dyncomp* self)
89 {
90 self->za1 = 0.f;
91 self->zr1 = 0.f;
92 self->zr2 = 0.f;
93 self->rms = 0.f;
94 self->gmin = 0.f;
95 self->gmax = 0.f;
96 self->newg = true;
97 }
98
99 static inline void
Dyncomp_set_ratio(Dyncomp * self,float r)100 Dyncomp_set_ratio (Dyncomp* self, float r)
101 {
102 self->p_rat = 0.5f * r;
103 }
104
105 static inline void
Dyncomp_set_inputgain(Dyncomp * self,float g)106 Dyncomp_set_inputgain (Dyncomp* self, float g)
107 {
108 if (g == self->l_ign) {
109 return;
110 }
111 self->l_ign = g;
112 #ifdef __USE_GNU
113 self->p_ign = exp10f (0.05f * g);
114 #else
115 self->p_ign = powf (10.0f, 0.05f * g);
116 #endif
117 }
118
119 static inline void
Dyncomp_set_threshold(Dyncomp * self,float t)120 Dyncomp_set_threshold (Dyncomp* self, float t)
121 {
122 if (t == self->l_thr) {
123 return;
124 }
125 self->l_thr = t;
126 /* Note that this is signal-power, hence .5 * 10^(x/10) */
127 #ifdef __USE_GNU
128 self->p_thr = 0.5f * exp10f (0.1f * t);
129 #else
130 self->p_thr = 0.5f * powf (10.0f, 0.1f * t);
131 #endif
132 }
133
134 static inline void
Dyncomp_set_hold(Dyncomp * self,bool hold)135 Dyncomp_set_hold (Dyncomp* self, bool hold)
136 {
137 self->hold = hold;
138 }
139
140 static inline void
Dyncomp_set_attack(Dyncomp * self,float a)141 Dyncomp_set_attack (Dyncomp* self, float a)
142 {
143 if (a == self->t_att) {
144 return;
145 }
146 self->t_att = a;
147 self->w_att = 0.5f / (self->sample_rate * a);
148 }
149
150 static inline void
Dyncomp_set_release(Dyncomp * self,float r)151 Dyncomp_set_release (Dyncomp* self, float r)
152 {
153 if (r == self->t_rel) {
154 return;
155 }
156 self->t_rel = r;
157 self->w_rel = 3.5f / (self->sample_rate * r);
158 }
159
160 static inline void
Dyncomp_get_gain(Dyncomp * self,float * gmin,float * gmax,float * rms)161 Dyncomp_get_gain (Dyncomp* self, float* gmin, float* gmax, float* rms)
162 {
163 *gmin = self->gmin * 8.68589f; /* 20 / log(10) */
164 *gmax = self->gmax * 8.68589f;
165 if (self->rms > 1e-8f) {
166 *rms = 10.f * log10f (2.f * self->rms);
167 } else {
168 *rms = -80;
169 }
170 self->newg = true;
171 }
172
173 static inline void
Dyncomp_init(Dyncomp * self,float sample_rate,uint32_t n_channels)174 Dyncomp_init (Dyncomp* self, float sample_rate, uint32_t n_channels)
175 {
176 self->sample_rate = sample_rate;
177 self->n_channels = n_channels;
178 self->norm_input = 1.f / n_channels;
179
180 self->ratio = 0.f;
181 self->p_rat = 0.f;
182
183 self->igain = 1.f;
184 self->p_ign = 1.f;
185 self->l_ign = 0.f;
186
187 self->p_thr = 0.05f;
188 self->l_thr = -10.f;
189
190 self->hold = false;
191
192 self->t_att = 0.f;
193 self->t_rel = 0.f;
194
195 self->w_rms = 5.f / sample_rate;
196 self->w_lpf = 160.f / sample_rate;
197
198 Dyncomp_set_attack (self, 0.01f);
199 Dyncomp_set_release (self, 0.03f);
200 Dyncomp_reset (self);
201 }
202
203 static inline void
Dyncomp_process(Dyncomp * self,uint32_t n_samples,float * inp[],float * out[])204 Dyncomp_process (Dyncomp* self, uint32_t n_samples, float* inp[], float* out[])
205 {
206 float gmin, gmax;
207
208 /* reset min/max gain report */
209 if (self->newg) {
210 gmax = -100.0f;
211 gmin = 100.0f;
212 self->newg = false;
213 } else {
214 gmax = self->gmax;
215 gmin = self->gmin;
216 }
217
218 /* interpolate input gain */
219 float g = self->igain;
220 const float g1 = self->p_ign;
221 float dg = g1 - g;
222 if (fabsf (dg) < 1e-5f || (g > 1.f && fabsf (dg) < 1e-3f)) {
223 g = g1;
224 dg = 0;
225 }
226
227 /* interpolate ratio */
228 float r = self->ratio;
229 const float r1 = self->p_rat;
230 float dr = r1 - r;
231 if (fabsf (dr) < 1e-5f) {
232 r = r1;
233 dr = 0;
234 }
235
236 /* localize variables */
237 float za1 = self->za1;
238 float zr1 = self->zr1;
239 float zr2 = self->zr2;
240
241 float rms = self->rms;
242
243 const float w_rms = self->w_rms;
244 const float w_lpf = self->w_lpf;
245 const float w_att = self->w_att;
246 const float w_rel = self->w_rel;
247 const float p_thr = self->p_thr;
248
249 const float p_hold = self->hold ? 2.f * p_thr : 0.f;
250
251 const uint32_t nc = self->n_channels;
252 const float n_1 = self->norm_input;
253
254 for (uint32_t j = 0; j < n_samples; ++j) {
255 /* update input gain */
256 if (dg != 0) {
257 g += w_lpf * (g1 - g);
258 }
259
260 /* Input/Key RMS */
261 float v = 0;
262 for (uint32_t i = 0; i < nc; ++i) {
263 const float x = g * inp[i][j];
264 v += x * x;
265 }
266
267 v *= n_1; // normalize *= 1 / (number of channels)
268
269 /* slow moving RMS, used for GUI level meter display */
270 rms += w_rms * (v - rms); // TODO: consider reporting range; 5ms integrate, 50ms min/max readout
271
272 /* calculate signal power relative to threshold, LPF using attack time constant */
273 za1 += w_att * (p_thr + v - za1);
274
275 /* hold release */
276 const bool hold = 0 != isless (za1, p_hold);
277
278 /* Note: za1 >= p_thr; so zr1, zr2 can't become denormal */
279 if (isless (zr1, za1)) {
280 zr1 = za1;
281 } else if (!hold) {
282 zr1 -= w_rel * zr1;
283 }
284
285 if (isless (zr2, za1)) {
286 zr2 = za1;
287 } else if (!hold) {
288 zr2 += w_rel * (zr1 - zr2);
289 }
290
291 /* update ratio */
292 if (dr != 0) {
293 r += w_lpf * (r1 - r);
294 }
295
296 /* Note: expf (a * logf (b)) == powf (b, a);
297 * however powf() is significantly slower
298 *
299 * Effective gain is (zr2) ^ (-ratio).
300 *
301 * with 0 <= ratio <= 0.5 and
302 * zr2 being low-pass (attack/release) filtered square of the key-signal.
303 */
304
305 float pg = -r * logf (20.0f * zr2);
306
307 /* store min/max gain in dB, report to UI */
308 gmax = fmaxf (gmax, pg);
309 gmin = fminf (gmin, pg);
310
311 pg = g * expf (pg);
312
313 /* apply gain factor to all channels */
314 for (uint32_t i = 0; i < nc; ++i) {
315 out[i][j] = pg * inp[i][j];
316 }
317 }
318
319 /* copy back variables */
320 self->igain = g;
321 self->ratio = r;
322
323 if (!isfinite (za1)) {
324 self->za1 = 0.f;
325 self->zr1 = 0.f;
326 self->zr2 = 0.f;
327 self->newg = true; /* reset gmin/gmax next cycle */
328 } else {
329 self->za1 = za1;
330 self->zr1 = zr1;
331 self->zr2 = zr2;
332 self->gmax = gmax;
333 self->gmin = gmin;
334 }
335
336 if (!isfinite (rms)) {
337 self->rms = 0.f;
338 } else if (rms > 10) {
339 self->rms = 10; // 20dBFS
340 } else {
341 self->rms = rms + 1e-12; // + denormal protection
342 }
343 }
344
345 /* ****************************************************************************/
346
347 typedef struct {
348 float* _port[DARC_LAST];
349
350 Dyncomp dyncomp;
351
352 float _gmin;
353 float _gmax;
354 float _rms;
355
356 uint32_t samplecnt;
357 uint32_t sampletme; // 50ms
358
359 #ifdef DISPLAY_INTERFACE
360 LV2_Inline_Display_Image_Surface surf;
361 cairo_surface_t* display;
362 LV2_Inline_Display* queue_draw;
363 cairo_pattern_t* mpat;
364 cairo_pattern_t* cpat;
365 uint32_t w, h;
366 float ui_gmin;
367 float ui_gmax;
368 #endif
369
370 } Darc;
371
372 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)373 instantiate (const LV2_Descriptor* descriptor,
374 double rate,
375 const char* bundle_path,
376 const LV2_Feature* const* features)
377 {
378 Darc* self = (Darc*)calloc (1, sizeof (Darc));
379
380 uint32_t n_channels;
381
382 if (!strcmp (descriptor->URI, DARC_URI "mono")) {
383 n_channels = 1;
384 } else if (!strcmp (descriptor->URI, DARC_URI "stereo")) {
385 n_channels = 2;
386 } else {
387 free (self);
388 return NULL;
389 }
390
391 #ifdef DISPLAY_INTERFACE
392 for (int i = 0; features[i]; ++i) {
393 if (!strcmp (features[i]->URI, LV2_INLINEDISPLAY__queue_draw)) {
394 self->queue_draw = (LV2_Inline_Display*)features[i]->data;
395 }
396 }
397 #endif
398
399 Dyncomp_init (&self->dyncomp, rate, n_channels);
400 self->sampletme = ceilf (rate * 0.05); // 50ms
401 self->samplecnt = self->sampletme;
402
403 return (LV2_Handle)self;
404 }
405
406 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)407 connect_port (LV2_Handle instance,
408 uint32_t port,
409 void* data)
410 {
411 Darc* self = (Darc*)instance;
412 if (port < DARC_LAST) {
413 self->_port[port] = (float*)data;
414 }
415 }
416
417 static void
activate(LV2_Handle instance)418 activate (LV2_Handle instance)
419 {
420 Darc* self = (Darc*)instance;
421 Dyncomp_reset (&self->dyncomp);
422 self->samplecnt = self->sampletme;
423 }
424
425 static void
run(LV2_Handle instance,uint32_t n_samples)426 run (LV2_Handle instance, uint32_t n_samples)
427 {
428 Darc* self = (Darc*)instance;
429
430 /* bypass/enable */
431 const bool enable = *self->_port[DARC_ENABLE] > 0;
432
433 if (enable) {
434 Dyncomp_set_inputgain (&self->dyncomp, *self->_port[DARC_INPUTGAIN]);
435 Dyncomp_set_threshold (&self->dyncomp, *self->_port[DARC_THRESHOLD]);
436 Dyncomp_set_ratio (&self->dyncomp, *self->_port[DARC_RATIO]);
437 Dyncomp_set_hold (&self->dyncomp, *self->_port[DARC_HOLD] > 0);
438 } else {
439 Dyncomp_set_inputgain (&self->dyncomp, 0);
440 Dyncomp_set_threshold (&self->dyncomp, -10.f);
441 Dyncomp_set_ratio (&self->dyncomp, 0);
442 Dyncomp_set_hold (&self->dyncomp, false);
443 }
444
445 Dyncomp_set_attack (&self->dyncomp, *self->_port[DARC_ATTACK]);
446 Dyncomp_set_release (&self->dyncomp, *self->_port[DARC_RELEASE]);
447
448 float* ins[2] = { self->_port[DARC_INPUT0], self->_port[DARC_INPUT1] };
449 float* outs[2] = { self->_port[DARC_OUTPUT0], self->_port[DARC_OUTPUT1] };
450
451 Dyncomp_process (&self->dyncomp, n_samples, ins, outs);
452
453 self->samplecnt += n_samples;
454 while (self->samplecnt >= self->sampletme) {
455 self->samplecnt -= self->sampletme;
456 Dyncomp_get_gain (&self->dyncomp, &self->_gmin, &self->_gmax, &self->_rms);
457
458 self->_gmin = fminf (40.f, fmaxf (-20.f, self->_gmin));
459 self->_gmax = fminf (40.f, fmaxf (-20.f, self->_gmax));
460 self->_rms = fminf (10.f, fmaxf (-80.f, self->_rms));
461
462 #ifdef DISPLAY_INTERFACE
463 if (self->queue_draw && (self->ui_gmin != self->_gmin || self->ui_gmax != self->_gmax)) {
464 self->ui_gmin = self->_gmin;
465 self->ui_gmax = self->_gmax;
466 self->queue_draw->queue_draw (self->queue_draw->handle);
467 }
468 #endif
469 }
470
471 *self->_port[DARC_GMIN] = self->_gmin;
472 *self->_port[DARC_GMAX] = self->_gmax;
473 *self->_port[DARC_RMS] = self->_rms;
474 }
475
476 static void
cleanup(LV2_Handle instance)477 cleanup (LV2_Handle instance)
478 {
479 Darc* self = (Darc*)instance;
480 #ifdef DISPLAY_INTERFACE
481 if (self->mpat) {
482 cairo_pattern_destroy (self->mpat);
483 }
484 if (self->cpat) {
485 cairo_pattern_destroy (self->cpat);
486 }
487 if (self->display) {
488 cairo_surface_destroy (self->display);
489 }
490 #endif
491 free (instance);
492 }
493
494 /* ****************************************************************************/
495
496 #ifdef WITH_SIGNATURE
497 #define RTK_URI DARC_URI
498 #include "gpg_init.c"
499 #include WITH_SIGNATURE
500 struct license_info license_infos = {
501 "x42-Compressor",
502 "http://x42-plugins.com/x42/x42-compressor"
503 };
504 #include "gpg_lv2ext.c"
505 #endif
506
507 #ifdef DISPLAY_INTERFACE
508 static void
create_pattern(Darc * self,const double w)509 create_pattern (Darc* self, const double w)
510 {
511 const int x0 = floor (w * 0.05);
512 const int x1 = ceil (w * 0.95);
513 const int wd = x1 - x0;
514
515 #define DEF(x) ((x0 + wd * ((x) + 20.) / 60.) / w)
516
517 cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, w, 0);
518 /* clang-format off */
519 cairo_pattern_add_color_stop_rgba (pat, 1.0, .0, .5, .0, 0);
520 cairo_pattern_add_color_stop_rgba (pat, DEF (40), .0, .5, .0, 0.5);
521 cairo_pattern_add_color_stop_rgba (pat, DEF (5), .0, .5, .0, 0.5);
522 cairo_pattern_add_color_stop_rgba (pat, DEF (-5), .5, .0, .0, 0.5);
523 cairo_pattern_add_color_stop_rgba (pat, DEF (-20), .5, .0, .0, 0.5);
524 cairo_pattern_add_color_stop_rgba (pat, 0.0, .5, .0, .0, 0);
525 /* clang-format on */
526 self->mpat = pat;
527
528 pat = cairo_pattern_create_linear (0.0, 0.0, w, 0);
529 /* clang-format off */
530 cairo_pattern_add_color_stop_rgba (pat, 1.0, .1, .9, .1, 0);
531 cairo_pattern_add_color_stop_rgba (pat, DEF (40), .1, .9, .1, 1);
532 cairo_pattern_add_color_stop_rgba (pat, DEF (5), .1, .9, .1, 1);
533 cairo_pattern_add_color_stop_rgba (pat, DEF (-5), .9, .9, .1, 1);
534 cairo_pattern_add_color_stop_rgba (pat, DEF (-20), .9, .9, .1, 1);
535 cairo_pattern_add_color_stop_rgba (pat, 0.0, .9, .9, .1, 0);
536 /* clang-format on */
537 self->cpat = pat;
538
539 #undef DEF
540 }
541
542 static LV2_Inline_Display_Image_Surface*
dpl_render(LV2_Handle handle,uint32_t w,uint32_t max_h)543 dpl_render (LV2_Handle handle, uint32_t w, uint32_t max_h)
544 {
545 #ifdef WITH_SIGNATURE
546 if (!is_licensed (handle)) {
547 return NULL;
548 }
549 #endif
550 uint32_t h = MAX (11, MIN (1 | (uint32_t)ceilf (w / 10.f), max_h));
551
552 Darc* self = (Darc*)handle;
553
554 if (!self->display || self->w != w || self->h != h) {
555 if (self->display)
556 cairo_surface_destroy (self->display);
557 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
558 self->w = w;
559 self->h = h;
560 if (self->mpat) {
561 cairo_pattern_destroy (self->mpat);
562 self->mpat = NULL;
563 }
564 if (self->cpat) {
565 cairo_pattern_destroy (self->cpat);
566 self->cpat = NULL;
567 }
568 }
569
570 if (!self->mpat || !self->cpat) {
571 create_pattern (self, w);
572 }
573
574 cairo_t* cr = cairo_create (self->display);
575 cairo_rectangle (cr, 0, 0, w, h);
576 cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
577 cairo_fill (cr);
578
579 const int x0 = floor (w * 0.05);
580 const int x1 = ceil (w * 0.95);
581 const int wd = x1 - x0;
582
583 cairo_set_line_width (cr, 1);
584 cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 1.0);
585
586 #define DEF(x) (rint (x0 + wd * ((x) + 20.) / 60.) - .5)
587 #define GRID(x) \
588 cairo_move_to (cr, DEF (x), 0); \
589 cairo_rel_line_to (cr, 0, h); \
590 cairo_stroke (cr)
591
592 GRID (-20);
593 GRID (-10);
594 GRID (0);
595 GRID (10);
596 GRID (20);
597 GRID (30);
598 GRID (40);
599
600 #undef GRID
601
602 cairo_rectangle (cr, x0, 2, wd, h - 5);
603 cairo_set_source (cr, self->mpat);
604 cairo_fill (cr);
605
606 if (1) {
607 float v0 = DEF (self->ui_gmin);
608 float v1 = DEF (self->ui_gmax);
609 cairo_rectangle (cr, v0 - 1, 2, 2. + v1 - v0, h - 5);
610 cairo_set_source (cr, self->cpat);
611 cairo_fill (cr);
612 } else { /* bypassed */
613 cairo_rectangle (cr, 0, 0, w, h);
614 cairo_set_source_rgba (cr, .2, .2, .2, 0.8);
615 cairo_fill (cr);
616 }
617
618 #undef DEF
619
620 /* finish surface */
621 cairo_destroy (cr);
622 cairo_surface_flush (self->display);
623 self->surf.width = cairo_image_surface_get_width (self->display);
624 self->surf.height = cairo_image_surface_get_height (self->display);
625 self->surf.stride = cairo_image_surface_get_stride (self->display);
626 self->surf.data = cairo_image_surface_get_data (self->display);
627
628 return &self->surf;
629 }
630 #endif
631
632 const void*
extension_data(const char * uri)633 extension_data (const char* uri)
634 {
635 #ifdef DISPLAY_INTERFACE
636 static const LV2_Inline_Display_Interface display = { dpl_render };
637 if (!strcmp (uri, LV2_INLINEDISPLAY__interface)) {
638 #if (defined _WIN32 && defined RTK_STATIC_INIT)
639 static int once = 0;
640 if (!once) {
641 once = 1;
642 gobject_init_ctor ();
643 }
644 #endif
645 return &display;
646 }
647 #endif
648 #ifdef WITH_SIGNATURE
649 LV2_LICENSE_EXT_C
650 #endif
651 return NULL;
652 }
653
654 static const LV2_Descriptor descriptor_mono = {
655 DARC_URI "mono",
656 instantiate,
657 connect_port,
658 activate,
659 run,
660 NULL,
661 cleanup,
662 extension_data
663 };
664
665 static const LV2_Descriptor descriptor_stereo = {
666 DARC_URI "stereo",
667 instantiate,
668 connect_port,
669 activate,
670 run,
671 NULL,
672 cleanup,
673 extension_data
674 };
675
676 /* clang-format off */
677 #undef LV2_SYMBOL_EXPORT
678 #ifdef _WIN32
679 # define LV2_SYMBOL_EXPORT __declspec(dllexport)
680 #else
681 # define LV2_SYMBOL_EXPORT __attribute__ ((visibility ("default")))
682 #endif
683 /* clang-format on */
684 LV2_SYMBOL_EXPORT
685 const LV2_Descriptor*
lv2_descriptor(uint32_t index)686 lv2_descriptor (uint32_t index)
687 {
688 switch (index) {
689 case 0:
690 return &descriptor_mono;
691 case 1:
692 return &descriptor_stereo;
693 default:
694 return NULL;
695 }
696 }
697