correctly initialize LTC transport master port latency (reversed boolean error)
[ardour.git] / libs / plugins / a-comp.lv2 / a-comp.c
1 /* a-comp
2  * Copyright (C) 2016 Damien Zammit <damien@zamaudio.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <math.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdbool.h>
19
20 #ifdef LV2_EXTENDED
21 #include <cairo/cairo.h>
22 #include "ardour/lv2_extensions.h"
23 #endif
24
25 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
26
27 #define ACOMP_URI               "urn:ardour:a-comp"
28 #define ACOMP_STEREO_URI        "urn:ardour:a-comp#stereo"
29
30 #define RESET_PEAK_AFTER_SECONDS 3
31
32 #ifndef M_PI
33 #  define M_PI 3.14159265358979323846
34 #endif
35
36 #ifdef COMPILER_MSVC
37 #include <float.h>
38 #define isfinite_local(val) (bool)_finite((double)val)
39 #else
40 #define isfinite_local isfinite
41 #endif
42
43 #ifndef FLT_EPSILON
44 #  define FLT_EPSILON 1.192093e-07
45 #endif
46
47 typedef enum {
48         ACOMP_ATTACK = 0,
49         ACOMP_RELEASE,
50         ACOMP_KNEE,
51         ACOMP_RATIO,
52         ACOMP_THRESHOLD,
53         ACOMP_MAKEUP,
54
55         ACOMP_GAINR,
56         ACOMP_INLEVEL,
57         ACOMP_OUTLEVEL,
58
59         ACOMP_SIDECHAIN,
60         ACOMP_ENABLE,
61         ACOMP_FULL_INLINEDISP,
62
63         ACOMP_A0,
64         ACOMP_A1,
65         ACOMP_A2,
66         ACOMP_A3,
67         ACOMP_A4,
68 } PortIndex;
69
70 typedef struct {
71         float* attack;
72         float* release;
73         float* knee;
74         float* ratio;
75         float* thresdb;
76         float* makeup;
77
78         float* gainr;
79         float* outlevel;
80         float* inlevel;
81
82         float* sidechain;
83         float* enable;
84         float* full_inline_display;
85
86         float* input0;
87         float* input1;
88         float* sc;
89         float* output0;
90         float* output1;
91
92         uint32_t n_channels;
93
94         float srate;
95
96         float makeup_gain;
97
98 #ifdef LV2_EXTENDED
99         LV2_Inline_Display_Image_Surface surf;
100         bool                     need_expose;
101         cairo_surface_t*         display;
102         LV2_Inline_Display*      queue_draw;
103         uint32_t                 w, h;
104
105         /* ports pointers are only valid during run so we'll
106          * have to cache them for the display, besides
107          * we do want to check for changes
108          */
109         float v_knee;
110         float v_ratio;
111         float v_thresdb;
112         float v_gainr;
113         float v_makeup;
114         float v_lvl_in;
115         float v_lvl_out;
116         float v_state_x;
117
118         bool v_full_inline_display;
119
120         float v_peakdb;
121         uint32_t peakdb_samples;
122 #endif
123 } AComp;
124
125 static LV2_Handle
126 instantiate(const LV2_Descriptor* descriptor,
127             double rate,
128             const char* bundle_path,
129             const LV2_Feature* const* features)
130 {
131         AComp* acomp = (AComp*)calloc(1, sizeof(AComp));
132
133         if (!strcmp (descriptor->URI, ACOMP_URI)) {
134                 acomp->n_channels = 1;
135         } else if (!strcmp (descriptor->URI, ACOMP_STEREO_URI)) {
136                 acomp->n_channels = 2;
137         } else {
138                 free (acomp);
139                 return NULL;
140         }
141
142         for (int i=0; features[i]; ++i) {
143 #ifdef LV2_EXTENDED
144                 if (!strcmp(features[i]->URI, LV2_INLINEDISPLAY__queue_draw)) {
145                         acomp->queue_draw = (LV2_Inline_Display*) features[i]->data;
146                 }
147 #endif
148         }
149
150         acomp->srate = rate;
151         acomp->makeup_gain = 1.f;
152 #ifdef LV2_EXTENDED
153         acomp->need_expose = true;
154         acomp->v_lvl_out = -70.f;
155 #endif
156
157         return (LV2_Handle)acomp;
158 }
159
160 static void
161 connect_port(LV2_Handle instance,
162              uint32_t port,
163              void* data)
164 {
165         AComp* acomp = (AComp*)instance;
166
167         switch ((PortIndex)port) {
168                 case ACOMP_ATTACK:
169                         acomp->attack = (float*)data;
170                         break;
171                 case ACOMP_RELEASE:
172                         acomp->release = (float*)data;
173                         break;
174                 case ACOMP_KNEE:
175                         acomp->knee = (float*)data;
176                         break;
177                 case ACOMP_RATIO:
178                         acomp->ratio = (float*)data;
179                         break;
180                 case ACOMP_THRESHOLD:
181                         acomp->thresdb = (float*)data;
182                         break;
183                 case ACOMP_MAKEUP:
184                         acomp->makeup = (float*)data;
185                         break;
186                 case ACOMP_GAINR:
187                         acomp->gainr = (float*)data;
188                         break;
189                 case ACOMP_OUTLEVEL:
190                         acomp->outlevel = (float*)data;
191                         break;
192                 case ACOMP_INLEVEL:
193                         acomp->inlevel = (float*)data;
194                         break;
195                 case ACOMP_SIDECHAIN:
196                         acomp->sidechain = (float*)data;
197                         break;
198                 case ACOMP_ENABLE:
199                         acomp->enable = (float*)data;
200                         break;
201                 case ACOMP_FULL_INLINEDISP:
202                         acomp->full_inline_display = (float*)data;
203                         break;
204                 default:
205                         break;
206         }
207 }
208
209 static void
210 connect_mono(LV2_Handle instance,
211              uint32_t port,
212              void* data)
213 {
214         AComp* acomp = (AComp*)instance;
215         connect_port (instance, port, data);
216
217         switch ((PortIndex)port) {
218                 case ACOMP_A0:
219                         acomp->input0 = (float*)data;
220                         break;
221                 case ACOMP_A1:
222                         acomp->sc = (float*)data;
223                         break;
224                 case ACOMP_A2:
225                         acomp->output0 = (float*)data;
226                         break;
227         default:
228                 break;
229         }
230 }
231
232 static void
233 connect_stereo(LV2_Handle instance,
234                uint32_t port,
235                void* data)
236 {
237         AComp* acomp = (AComp*)instance;
238         connect_port (instance, port, data);
239
240         switch ((PortIndex)port) {
241                 case ACOMP_A0:
242                         acomp->input0 = (float*)data;
243                         break;
244                 case ACOMP_A1:
245                         acomp->input1 = (float*)data;
246                         break;
247                 case ACOMP_A2:
248                         acomp->sc = (float*)data;
249                         break;
250                 case ACOMP_A3:
251                         acomp->output0 = (float*)data;
252                         break;
253                 case ACOMP_A4:
254                         acomp->output1 = (float*)data;
255                         break;
256         default:
257                 break;
258         }
259 }
260
261 // Force already-denormal float value to zero
262 static inline float
263 sanitize_denormal(float value) {
264         if (!isnormal(value)) {
265                 value = 0.f;
266         }
267         return value;
268 }
269
270 static inline float
271 from_dB(float gdb) {
272         return (exp(gdb/20.f*log(10.f)));
273 }
274
275 static inline float
276 to_dB(float g) {
277         return (20.f*log10(g));
278 }
279
280 static void
281 activate(LV2_Handle instance)
282 {
283         AComp* acomp = (AComp*)instance;
284
285         *(acomp->gainr) = 0.0f;
286         *(acomp->outlevel) = -70.0f;
287         *(acomp->inlevel) = -160.f;
288
289 #ifdef LV2_EXTENDED
290         acomp->v_peakdb = -160.f;
291         acomp->peakdb_samples = 0;
292 #endif
293 }
294
295 static void
296 run(LV2_Handle instance, uint32_t n_samples)
297 {
298         AComp* acomp = (AComp*)instance;
299
300         const float* const ins[2] = { acomp->input0, acomp->input1 };
301         const float* const sc = acomp->sc;
302         float* const outs[2] = { acomp->output0, acomp->output1 };
303
304         float srate = acomp->srate;
305         float width = (6.f * *(acomp->knee)) + 0.01;
306         float attack_coeff = exp(-1000.f/(*(acomp->attack) * srate));
307         float release_coeff = exp(-1000.f/(*(acomp->release) * srate));
308
309         float max_out = 0.f;
310         float Lgain = 1.f;
311         float Lxg, Lyg;
312         float current_gainr;
313         float old_gainr = *acomp->gainr;
314
315         int usesidechain = (*(acomp->sidechain) <= 0.f) ? 0 : 1;
316         uint32_t i;
317         float ingain;
318         float sc0;
319         float maxabs;
320
321         uint32_t n_channels = acomp->n_channels;
322
323         float ratio = *acomp->ratio;
324         float thresdb = *acomp->thresdb;
325         float makeup = *acomp->makeup;
326         float makeup_target = from_dB(makeup);
327         float makeup_gain = acomp->makeup_gain;
328
329         const float tau = (1.0 - exp (-2.f * M_PI * 25.f / acomp->srate));
330
331         if (*acomp->enable <= 0) {
332                 ratio = 1.f;
333                 thresdb = 0.f;
334                 makeup = 0.f;
335                 makeup_target = 1.f;
336         }
337
338 #ifdef LV2_EXTENDED
339         if (acomp->v_knee != *acomp->knee) {
340                 acomp->v_knee = *acomp->knee;
341                 acomp->need_expose = true;
342         }
343
344         if (acomp->v_ratio != ratio) {
345                 acomp->v_ratio = ratio;
346                 acomp->need_expose = true;
347         }
348
349         if (acomp->v_thresdb != thresdb) {
350                 acomp->v_thresdb = thresdb;
351                 acomp->need_expose = true;
352         }
353
354         if (acomp->v_makeup != makeup) {
355                 acomp->v_makeup = makeup;
356                 acomp->need_expose = true;
357         }
358
359         bool full_inline = *acomp->full_inline_display > 0.5;
360         if (full_inline != acomp->v_full_inline_display) {
361                 acomp->v_full_inline_display = full_inline;
362                 acomp->need_expose = true;
363         }
364 #endif
365
366         float in_peak_db = -160.f;
367         float max_gainr = 0.f;
368
369         for (i = 0; i < n_samples; i++) {
370                 maxabs = 0.f;
371                 for (uint32_t c=0; c<n_channels; ++c) {
372                         maxabs = fmaxf(fabsf(ins[c][i]), maxabs);
373                 }
374                 sc0 = sc[i];
375                 ingain = usesidechain ? fabs(sc0) : maxabs;
376                 Lyg = 0.f;
377                 Lxg = (ingain==0.f) ? -160.f : to_dB(ingain);
378                 Lxg = sanitize_denormal(Lxg);
379                 if (Lxg > in_peak_db) {
380                         in_peak_db = Lxg;
381                 }
382
383                 if (2.f*(Lxg-thresdb) < -width) {
384                         Lyg = Lxg;
385                 } else if (2.f*(Lxg-thresdb) > width) {
386                         Lyg = thresdb + (Lxg-thresdb)/ratio;
387                         Lyg = sanitize_denormal(Lyg);
388                 } else {
389                         Lyg = Lxg + (1.f/ratio-1.f)*(Lxg-thresdb+width/2.f)*(Lxg-thresdb+width/2.f)/(2.f*width);
390                 }
391
392                 current_gainr = Lxg - Lyg;
393
394                 if (current_gainr < old_gainr) {
395                         current_gainr = release_coeff*old_gainr + (1.f-release_coeff)*current_gainr;
396                 } else if (current_gainr > old_gainr) {
397                         current_gainr = attack_coeff*old_gainr + (1.f-attack_coeff)*current_gainr;
398                 }
399
400                 current_gainr = sanitize_denormal(current_gainr);
401
402                 Lgain = from_dB(-current_gainr);
403
404                 old_gainr = current_gainr;
405
406                 *(acomp->gainr) = current_gainr;
407                 if (current_gainr > max_gainr) {
408                         max_gainr = current_gainr;
409                 }
410
411                 makeup_gain += tau * (makeup_target - makeup_gain);
412
413                 for (uint32_t c=0; c<n_channels; ++c) {
414                         float out = ins[c][i] * Lgain * makeup_gain;
415                         outs[c][i] = out;
416                         out = fabsf (out);
417                         if (out > max_out) {
418                                 max_out = out;
419                                 sanitize_denormal(max_out);
420                         }
421                 }
422         }
423
424         if (fabsf(tau * (makeup_gain - makeup_target)) < FLT_EPSILON*makeup_gain) {
425                 makeup_gain = makeup_target;
426         }
427
428         *(acomp->outlevel) = (max_out < 0.0056f) ? -70.f : to_dB(max_out);
429         *(acomp->inlevel) = in_peak_db;
430         acomp->makeup_gain = makeup_gain;
431
432 #ifdef LV2_EXTENDED
433         acomp->v_gainr = max_gainr;
434
435         if (in_peak_db > acomp->v_peakdb) {
436                 acomp->v_peakdb = in_peak_db;
437                 acomp->peakdb_samples = 0;
438         } else {
439                 acomp->peakdb_samples += n_samples;
440                 if ((float)acomp->peakdb_samples/acomp->srate > RESET_PEAK_AFTER_SECONDS) {
441                         acomp->v_peakdb = in_peak_db;
442                         acomp->peakdb_samples = 0;
443                         acomp->need_expose = true;
444                 }
445         }
446
447         const float v_lvl_in = in_peak_db;
448         const float v_lvl_out = *acomp->outlevel;
449
450         float state_x;
451
452         const float knee_lim_gr = (1.f - 1.f/ratio) * width/2.f;
453
454         if (acomp->v_gainr > knee_lim_gr) {
455                 state_x = acomp->v_gainr / (1.f - 1.f/ratio) + thresdb;
456         } else {
457                 state_x = sqrt ( (2.f*width*acomp->v_gainr) / (1.f-1.f/ratio) ) + thresdb - width/2.f;
458         }
459
460         if (fabsf (acomp->v_lvl_out - v_lvl_out) >= .1f ||
461             fabsf (acomp->v_lvl_in - v_lvl_in) >= .1f ||
462             fabsf (acomp->v_state_x - state_x) >= .1f ) {
463                 // >= 0.1dB difference
464                 acomp->need_expose = true;
465                 acomp->v_lvl_in = v_lvl_in;
466                 acomp->v_lvl_out = v_lvl_out;
467                 acomp->v_state_x = state_x;
468         }
469         if (acomp->need_expose && acomp->queue_draw) {
470                 acomp->need_expose = false;
471                 acomp->queue_draw->queue_draw (acomp->queue_draw->handle);
472         }
473 #endif
474 }
475
476 static void
477 deactivate(LV2_Handle instance)
478 {
479         activate(instance);
480 }
481
482 static void
483 cleanup(LV2_Handle instance)
484 {
485 #ifdef LV2_EXTENDED
486         AComp* acomp = (AComp*)instance;
487         if (acomp->display) {
488                 cairo_surface_destroy (acomp->display);
489         }
490 #endif
491
492         free(instance);
493 }
494
495
496 #ifndef MIN
497 #define MIN(A,B) ((A) < (B)) ? (A) : (B)
498 #endif
499
500 #ifdef LV2_EXTENDED
501 static float
502 comp_curve (const AComp* self, float xg) {
503         const float knee = self->v_knee;
504         const float ratio = self->v_ratio;
505         const float thresdb = self->v_thresdb;
506         const float makeup = self->v_makeup;
507
508         const float width = 6.f * knee + 0.01f;
509         float yg = 0.f;
510
511         if (2.f * (xg - thresdb) < -width) {
512                 yg = xg;
513         } else if (2.f * (xg - thresdb) > width) {
514                 yg = thresdb + (xg - thresdb) / ratio;
515         } else {
516                 yg = xg + (1.f / ratio - 1.f ) * (xg - thresdb + width / 2.f) * (xg - thresdb + width / 2.f) / (2.f * width);
517         }
518
519         yg += makeup;
520
521         return yg;
522 }
523
524
525 #include "dynamic_display.c"
526
527 static void
528 render_inline_full (cairo_t* cr, const AComp* self)
529 {
530         const float w = self->w;
531         const float h = self->h;
532
533         const float makeup_thres = self->v_thresdb + self->v_makeup;
534
535         draw_grid (cr, w,h);
536
537         if (self->v_thresdb < 0) {
538                 const float y = -.5 + floorf (h * ((makeup_thres - 10.f) / -70.f));
539                 cairo_move_to (cr, 0, y);
540                 cairo_line_to (cr, w, y);
541                 cairo_stroke (cr);
542         }
543
544         draw_GR_bar (cr, w,h, self->v_gainr);
545
546         // draw state
547         cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
548
549         const float state_x = w * (1.f - (10.f-self->v_state_x)/70.f);
550         const float state_y = h * (comp_curve (self, self->v_state_x) - 10.f) / -70.f;
551
552         cairo_arc (cr, state_x, state_y, 3.f, 0.f, 2.f*M_PI);
553         cairo_fill (cr);
554
555         // draw curve
556         cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
557         cairo_move_to (cr, 0, h);
558
559         for (uint32_t x = 0; x < w; ++x) {
560                 // plot -60..+10  dB
561                 const float x_db = 70.f * (-1.f + x / (float)w) + 10.f;
562                 const float y_db = comp_curve (self, x_db) - 10.f;
563                 const float y = h * (y_db / -70.f);
564                 cairo_line_to (cr, x, y);
565         }
566         cairo_stroke_preserve (cr);
567
568         cairo_line_to (cr, w, h);
569         cairo_close_path (cr);
570         cairo_clip (cr);
571
572         // draw signal level & reduction/gradient
573         const float top = comp_curve (self, 0) - 10.f;
574         cairo_pattern_t* pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, h);
575         if (top > makeup_thres - 10.f) {
576                 cairo_pattern_add_color_stop_rgba (pat, 0.0, 0.8, 0.1, 0.1, 0.5);
577                 cairo_pattern_add_color_stop_rgba (pat, top / -70.f, 0.8, 0.1, 0.1, 0.5);
578         }
579         if (self->v_knee > 0) {
580                 cairo_pattern_add_color_stop_rgba (pat, ((makeup_thres -10.f) / -70.f), 0.7, 0.7, 0.2, 0.5);
581                 cairo_pattern_add_color_stop_rgba (pat, ((makeup_thres - self->v_knee - 10.f) / -70.f), 0.5, 0.5, 0.5, 0.5);
582         } else {
583                 cairo_pattern_add_color_stop_rgba (pat, ((makeup_thres - 10.f)/ -70.f), 0.7, 0.7, 0.2, 0.5);
584                 cairo_pattern_add_color_stop_rgba (pat, ((makeup_thres - 10.01f) / -70.f), 0.5, 0.5, 0.5, 0.5);
585         }
586         cairo_pattern_add_color_stop_rgba (pat, 1.0, 0.5, 0.5, 0.5, 0.5);
587
588         // maybe cut off at x-position?
589         const float x = w * (self->v_lvl_in + 60) / 70.f;
590         const float y = x + h*self->v_makeup;
591         cairo_rectangle (cr, 0, h - y, x, y);
592         if (self->v_ratio > 1.0) {
593                 cairo_set_source (cr, pat);
594         } else {
595                 cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
596         }
597         cairo_fill (cr);
598
599         cairo_pattern_destroy (pat); // TODO cache pattern
600 }
601
602 static void
603 render_inline_only_bars (cairo_t* cr, const AComp* self)
604 {
605         draw_inline_bars (cr, self->w, self->h,
606                           self->v_thresdb, self->v_ratio,
607                           self->v_peakdb, self->v_gainr,
608                           self->v_lvl_in, self->v_lvl_out);
609 }
610
611 static LV2_Inline_Display_Image_Surface *
612 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
613 {
614         AComp* self = (AComp*)instance;
615
616         uint32_t h = MIN (w, max_h);
617         if (w < 200 && !self->v_full_inline_display) {
618                 h = MIN (40, max_h);
619         }
620
621         if (!self->display || self->w != w || self->h != h) {
622                 if (self->display) cairo_surface_destroy(self->display);
623                 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
624                 self->w = w;
625                 self->h = h;
626         }
627
628         cairo_t* cr = cairo_create (self->display);
629
630         if (w >= 200 || self->v_full_inline_display) {
631                 render_inline_full (cr, self);
632         } else {
633                 render_inline_only_bars (cr, self);
634         }
635
636         cairo_destroy (cr);
637
638         cairo_surface_flush (self->display);
639         self->surf.width = cairo_image_surface_get_width (self->display);
640         self->surf.height = cairo_image_surface_get_height (self->display);
641         self->surf.stride = cairo_image_surface_get_stride (self->display);
642         self->surf.data = cairo_image_surface_get_data  (self->display);
643
644         return &self->surf;
645 }
646 #endif
647
648 static const void*
649 extension_data(const char* uri)
650 {
651 #ifdef LV2_EXTENDED
652         static const LV2_Inline_Display_Interface display  = { render_inline };
653         if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
654                 return &display;
655         }
656 #endif
657         return NULL;
658 }
659
660 static const LV2_Descriptor descriptor_mono = {
661         ACOMP_URI,
662         instantiate,
663         connect_mono,
664         activate,
665         run,
666         deactivate,
667         cleanup,
668         extension_data
669 };
670
671 static const LV2_Descriptor descriptor_stereo = {
672         ACOMP_STEREO_URI,
673         instantiate,
674         connect_stereo,
675         activate,
676         run,
677         deactivate,
678         cleanup,
679         extension_data
680 };
681
682 LV2_SYMBOL_EXPORT
683 const LV2_Descriptor*
684 lv2_descriptor(uint32_t index)
685 {
686         switch (index) {
687         case 0:
688                 return &descriptor_mono;
689         case 1:
690                 return &descriptor_stereo;
691         default:
692                 return NULL;
693         }
694 }