From 59775df9be375a249b3c4cbdc7e825eee27c393e Mon Sep 17 00:00:00 2001 From: Johannes Mueller Date: Thu, 13 Jul 2017 21:28:17 +0200 Subject: Simplified inline display if the channel strip is not wide enough 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 | 148 ++++++++++++++++++++++++++++++++++----- 1 file changed, 131 insertions(+), 17 deletions(-) diff --git a/libs/plugins/a-comp.lv2/a-comp.c b/libs/plugins/a-comp.lv2/a-comp.c index bb282f962c..80985715e7 100644 --- a/libs/plugins/a-comp.lv2/a-comp.c +++ b/libs/plugins/a-comp.lv2/a-comp.c @@ -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); -- cgit v1.2.3