Simplified inline display if the channel strip is not wide enough
authorJohannes Mueller <github@johannes-mueller.org>
Thu, 13 Jul 2017 19:28:17 +0000 (21:28 +0200)
committerRobin Gareus <robin@gareus.org>
Mon, 31 Jul 2017 19:31:22 +0000 (21:31 +0200)
If the width of the display area is below 200 px, we switch from the graph
display to displaying only two bars, one for output level and one for gain
reduction. In the bar mode we also visualize threshold and ratio.

libs/plugins/a-comp.lv2/a-comp.c

index bb282f962c6d92660448637e131ba92b84026f6c..80985715e77294ded39286b4e0270deec8a8b999 100644 (file)
@@ -129,6 +129,7 @@ instantiate(const LV2_Descriptor* descriptor,
        acomp->tau = (1.0 - exp (-2.f * M_PI * 25.f / acomp->srate));
 #ifdef LV2_EXTENDED
        acomp->need_expose = true;
+       acomp->v_lvl_out = -70.f;
 #endif
 
        return (LV2_Handle)acomp;
@@ -394,7 +395,8 @@ run_mono(LV2_Handle instance, uint32_t n_samples)
                // >= 1dB difference
                acomp->need_expose = true;
                acomp->v_lvl_in = v_lvl_in;
-               acomp->v_lvl_out = v_lvl_out - to_dB(makeup_gain);
+               const float relax_coef = exp(-(float)n_samples/srate);
+               acomp->v_lvl_out = fmaxf (v_lvl_out, relax_coef*acomp->v_lvl_out + (1.f-relax_coef)*v_lvl_out);
        }
        if (acomp->need_expose && acomp->queue_draw) {
                acomp->need_expose = false;
@@ -547,7 +549,8 @@ run_stereo(LV2_Handle instance, uint32_t n_samples)
                // >= 1dB difference
                acomp->need_expose = true;
                acomp->v_lvl_in = v_lvl_in;
-               acomp->v_lvl_out = v_lvl_out - to_dB(makeup_gain);
+               const float relax_coef = exp(-2.0*n_samples/srate);
+               acomp->v_lvl_out = fmaxf (v_lvl_out, relax_coef*acomp->v_lvl_out + (1.f-relax_coef)*v_lvl_out);
        }
        if (acomp->need_expose && acomp->queue_draw) {
                acomp->need_expose = false;
@@ -582,7 +585,7 @@ cleanup(LV2_Handle instance)
 
 #ifdef LV2_EXTENDED
 static float
-comp_curve (AComp* self, float xg) {
+comp_curve (const AComp* self, float xg) {
        const float knee = self->v_knee;
        const float ratio = self->v_ratio;
        const float thresdb = self->v_thresdb;
@@ -604,23 +607,14 @@ comp_curve (AComp* self, float xg) {
        return yg;
 }
 
-static LV2_Inline_Display_Image_Surface *
-render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
+static void
+render_inline_full (cairo_t* cr, const AComp* self)
 {
-       AComp* self = (AComp*)instance;
-       uint32_t h = MIN (w, max_h);
+       const float w = self->w;
+       const float h = self->h;
 
        const float makeup_thres = self->v_thresdb + self->v_makeup;
 
-       if (!self->display || self->w != w || self->h != h) {
-               if (self->display) cairo_surface_destroy(self->display);
-               self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
-               self->w = w;
-               self->h = h;
-       }
-
-       cairo_t* cr = cairo_create (self->display);
-
        // clear background
        cairo_rectangle (cr, 0, 0, w, h);
        cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
@@ -737,10 +731,130 @@ render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
        cairo_fill (cr);
 
        cairo_pattern_destroy (pat); // TODO cache pattern
+}
+
+static void
+render_inline_only_bars (cairo_t* cr, const AComp* self)
+{
+       const float w = self->w;
+       const float h = self->h;
+
+       cairo_rectangle (cr, 0, 0, w, h);
+       cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
+       cairo_fill (cr);
+
+       cairo_set_line_width (cr, 1.0);
+
+       cairo_save (cr);
+
+       const float ht = 0.333f * h;
+
+       const float x1 = w*0.05;
+       const float wd = w - 2.0f*x1;
+
+       const float y1 = 0.1*h;
+       const float y2 = h - y1 - ht;
+
+       cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
+
+       cairo_rectangle (cr, x1, y1, wd, ht);
+       cairo_fill (cr);
+
+       cairo_rectangle (cr, x1, y2, wd, ht);
+       cairo_fill (cr);
+
+       cairo_set_source_rgba (cr, 0.75, 0.0, 0.0, 1.0);
+       const float w_gr = (self->v_gainr > 60.f) ? wd : wd * self->v_gainr * (1.f/60.f);
+       cairo_rectangle (cr, x1+wd-w_gr, y2, w_gr, ht);
+       cairo_fill (cr);
+
+       if (self->v_lvl_out > -60.f) {
+               if (self->v_lvl_out > 10.f) {
+                       cairo_set_source_rgba (cr, 0.75, 0.0, 0.0, 1.0);
+               } else if (self->v_lvl_out > 0.f) {
+                       cairo_set_source_rgba (cr, 0.66, 0.66, 0.0, 1.0);
+               } else {
+                       cairo_set_source_rgba (cr, 0.0, 0.66, 0.0, 1.0);
+               }
+               const float w_g = (self->v_lvl_out > 10.f) ? wd : wd * (60.f+self->v_lvl_out) / 70.f;
+               cairo_rectangle (cr, x1, y1, w_g, ht);
+               cairo_fill (cr);
+       }
+
+       cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
+
+       const float tck = 0.25*ht;
+
+       for (uint32_t d = 1; d < 7; ++d) {
+               const float x = x1 + (d * wd * (10.f / 70.f));
+
+               cairo_move_to (cr, x, y1);
+               cairo_line_to (cr, x, y1+tck);
+
+               cairo_move_to (cr, x, y1+ht);
+               cairo_line_to (cr, x, y1+ht-tck);
+
+               cairo_move_to (cr, x, y2);
+               cairo_line_to (cr, x, y2+tck);
+
+               cairo_move_to (cr, x, y2+ht);
+               cairo_line_to (cr, x, y2+ht-tck);
+       }
+
+       cairo_set_line_width (cr, 2.0);
+
+       const float x_0dB = x1 + wd*(60.f/70.f);
+
+       cairo_move_to (cr, x_0dB, y1);
+       cairo_line_to (cr, x_0dB, y1+ht);
+
+       cairo_rectangle (cr, x1, y1, wd, ht);
+       cairo_rectangle (cr, x1, y2, wd, ht);
+       cairo_stroke (cr);
+
+       // visualize threshold
+       const float tr = x1 + wd * (60.f+self->v_thresdb) / 70.f;
+       cairo_set_source_rgba (cr, 0.95, 0.95, 0.0, 1.0);
+       cairo_move_to (cr, tr, y1);
+       cairo_line_to (cr, tr, y1+ht);
+       cairo_stroke (cr);
+
+       // visualize ratio
+       const float reduced_0dB = self->v_thresdb * (1.f - 1.f/self->v_ratio);
+       const float rt = x1 + wd * (60.f+reduced_0dB) / 70.f;
+       cairo_set_source_rgba (cr, 0.95, 0.0, 0.0, 1.0);
+       cairo_move_to (cr, rt, y1);
+       cairo_line_to (cr, rt, y1+ht);
+       cairo_stroke (cr);
+}
 
+static LV2_Inline_Display_Image_Surface *
+render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
+{
+       AComp* self = (AComp*)instance;
+
+       uint32_t h = MIN (w, max_h);
+       if (w < 200) {
+               h = 40;
+       }
+
+       if (!self->display || self->w != w || self->h != h) {
+               if (self->display) cairo_surface_destroy(self->display);
+               self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+               self->w = w;
+               self->h = h;
+       }
+
+       cairo_t* cr = cairo_create (self->display);
+
+       if (w >= 200) {
+               render_inline_full (cr, self);
+       } else {
+               render_inline_only_bars (cr, self);
+       }
 
-       // create RGBA surface
        cairo_destroy (cr);
+
        cairo_surface_flush (self->display);
        self->surf.width = cairo_image_surface_get_width (self->display);
        self->surf.height = cairo_image_surface_get_height (self->display);