diff options
-rw-r--r-- | libs/plugins/a-comp.lv2/a-comp.c | 148 |
1 files 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); |