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