2 * Copyright (C) 2016 Damien Zammit <damien@zamaudio.com>
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.
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.
16 #define _GNU_SOURCE // needed for M_PI
26 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
29 #include <cairo/cairo.h>
30 #include "ardour/lv2_extensions.h"
33 #define AEQ_URI "urn:ardour:a-eq"
37 #define MIN(A,B) ((A) < (B)) ? (A) : (B)
72 return (20.f*log10(g));
77 return (exp(gdb/20.f*log(10.f)));
87 static void linear_svf_reset(struct linear_svf *self)
89 self->s[0] = self->s[1] = 0.0;
106 struct linear_svf v_filter[BANDS];
110 float v_filtog[BANDS];
118 LV2_Inline_Display_Image_Surface surf;
119 cairo_surface_t* display;
120 LV2_Inline_Display* queue_draw;
126 instantiate(const LV2_Descriptor* descriptor,
128 const char* bundle_path,
129 const LV2_Feature* const* features)
132 Aeq* aeq = (Aeq*)malloc(sizeof(Aeq));
136 for (int i=0; features[i]; ++i) {
137 if (!strcmp(features[i]->URI, LV2_INLINEDISPLAY__queue_draw)) {
138 aeq->queue_draw = (LV2_Inline_Display*) features[i]->data;
143 for (i = 0; i < BANDS; i++)
144 linear_svf_reset(&aeq->v_filter[i]);
146 aeq->need_expose = true;
149 return (LV2_Handle)aeq;
153 connect_port(LV2_Handle instance,
157 Aeq* aeq = (Aeq*)instance;
159 switch ((PortIndex)port) {
161 aeq->shelftogl = (float*)data;
164 aeq->f0[0] = (float*)data;
167 aeq->g[0] = (float*)data;
170 aeq->f0[1] = (float*)data;
173 aeq->g[1] = (float*)data;
176 aeq->bw[1] = (float*)data;
179 aeq->f0[2] = (float*)data;
182 aeq->g[2] = (float*)data;
185 aeq->bw[2] = (float*)data;
188 aeq->f0[3] = (float*)data;
191 aeq->g[3] = (float*)data;
194 aeq->bw[3] = (float*)data;
197 aeq->f0[4] = (float*)data;
200 aeq->g[4] = (float*)data;
203 aeq->bw[4] = (float*)data;
206 aeq->shelftogh = (float*)data;
209 aeq->f0[5] = (float*)data;
212 aeq->g[5] = (float*)data;
215 aeq->master = (float*)data;
218 aeq->filtog[0] = (float*)data;
221 aeq->filtog[1] = (float*)data;
224 aeq->filtog[2] = (float*)data;
227 aeq->filtog[3] = (float*)data;
230 aeq->filtog[4] = (float*)data;
233 aeq->filtog[5] = (float*)data;
236 aeq->input = (float*)data;
239 aeq->output = (float*)data;
245 activate(LV2_Handle instance)
248 Aeq* aeq = (Aeq*)instance;
250 for (i = 0; i < BANDS; i++)
251 linear_svf_reset(&aeq->v_filter[i]);
255 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
257 static void linear_svf_set_hp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
259 double f0 = (double)cutoff;
260 double q = (double)resonance;
261 double sr = (double)sample_rate;
263 self->g = tan(M_PI * (f0 / sr));
266 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
267 self->a[1] = self->g * self->a[0];
268 self->a[2] = self->g * self->a[1];
271 self->m[1] = -self->k;
275 static void linear_svf_set_lp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
277 double f0 = (double)cutoff;
278 double q = (double)resonance;
279 double sr = (double)sample_rate;
281 self->g = tan(M_PI * (f0 / sr));
284 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
285 self->a[1] = self->g * self->a[0];
286 self->a[2] = self->g * self->a[1];
293 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
295 double f0 = (double)cutoff;
296 double q = (double)pow(2.0, 1.0 / bandwidth) / (pow(2.0, bandwidth) - 1.0);
297 double sr = (double)sample_rate;
298 double A = pow(10.0, gdb/40.0);
300 self->g = tan(M_PI * (f0 / sr));
301 self->k = 1.0 / (q * A);
303 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
304 self->a[1] = self->g * self->a[0];
305 self->a[2] = self->g * self->a[1];
308 self->m[1] = self->k * (A * A - 1.0);
312 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
314 double f0 = (double)cutoff;
315 double q = (double)resonance;
316 double sr = (double)sample_rate;
317 double A = pow(10.0, gdb/40.0);
319 self->g = tan(M_PI * (f0 / sr));
322 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
323 self->a[1] = self->g * self->a[0];
324 self->a[2] = self->g * self->a[1];
327 self->m[1] = self->k * (1.0 - A) * A;
328 self->m[2] = 1.0 - A * A;
331 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
333 double f0 = (double)cutoff;
334 double q = (double)resonance;
335 double sr = (double)sample_rate;
336 double A = pow(10.0, gdb/40.0);
338 self->g = tan(M_PI * (f0 / sr));
341 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
342 self->a[1] = self->g * self->a[0];
343 self->a[2] = self->g * self->a[1];
346 self->m[1] = self->k * (A - 1.0);
347 self->m[2] = A * A - 1.0;
350 static float run_linear_svf(struct linear_svf *self, float in)
353 double din = (double)in;
356 v[2] = din - self->s[1];
357 v[0] = (self->a[0] * self->s[0]) + (self->a[1] * v[2]);
358 v[1] = self->s[1] + (self->a[1] * self->s[0]) + (self->a[2] * v[2]);
360 self->s[0] = (2.0 * v[0]) - self->s[0];
361 self->s[1] = (2.0 * v[1]) - self->s[1];
363 out = (self->m[0] * din)
364 + (self->m[1] * v[0])
365 + (self->m[2] * v[1]);
371 run(LV2_Handle instance, uint32_t n_samples)
373 Aeq* aeq = (Aeq*)instance;
375 const float* const input = aeq->input;
376 float* const output = aeq->output;
378 float srate = aeq->srate;
382 if (*(aeq->shelftogl) > 0.5) {
383 linear_svf_set_lowshelf(&aeq->v_filter[0], *(aeq->g[0]), srate, *(aeq->f0[0]), 0.7071068);
385 linear_svf_set_hp(&aeq->v_filter[0], srate, *(aeq->f0[0]), 0.7071068);
387 linear_svf_set_peq(&aeq->v_filter[1], *(aeq->g[1]), srate, *(aeq->f0[1]), *(aeq->bw[1]));
388 linear_svf_set_peq(&aeq->v_filter[2], *(aeq->g[2]), srate, *(aeq->f0[2]), *(aeq->bw[2]));
389 linear_svf_set_peq(&aeq->v_filter[3], *(aeq->g[3]), srate, *(aeq->f0[3]), *(aeq->bw[3]));
390 linear_svf_set_peq(&aeq->v_filter[4], *(aeq->g[4]), srate, *(aeq->f0[4]), *(aeq->bw[4]));
392 if (*(aeq->shelftogh) > 0.5) {
393 linear_svf_set_highshelf(&aeq->v_filter[5], *(aeq->g[5]), srate, *(aeq->f0[5]), 0.7071068);
395 linear_svf_set_lp(&aeq->v_filter[5], srate, *(aeq->f0[5]), 0.7071068);
398 for (i = 0; i < n_samples; i++) {
401 for (j = 0; j < BANDS; j++) {
402 if (*(aeq->filtog[j]) > 0.5)
403 out = run_linear_svf(&aeq->v_filter[j], out);
405 output[i] = out * from_dB(*(aeq->master));
408 for (i = 0; i < BANDS; i++) {
409 if (aeq->v_f0[i] != *(aeq->f0[i])) {
410 aeq->v_f0[i] = *(aeq->f0[i]);
411 aeq->need_expose = true;
413 if (aeq->v_g[i] != *(aeq->g[i])) {
414 aeq->v_g[i] = *(aeq->g[i]);
415 aeq->need_expose = true;
417 if (i != 0 && i != 5 && aeq->v_bw[i] != *(aeq->bw[i])) {
418 aeq->v_bw[i] = *(aeq->bw[i]);
419 aeq->need_expose = true;
421 if (aeq->v_filtog[i] != *(aeq->filtog[i])) {
422 aeq->v_filtog[i] = *(aeq->filtog[i]);
423 aeq->need_expose = true;
425 if (aeq->v_shelftogl != *(aeq->shelftogl)) {
426 aeq->v_shelftogl = *(aeq->shelftogl);
427 aeq->need_expose = true;
429 if (aeq->v_shelftogh != *(aeq->shelftogh)) {
430 aeq->v_shelftogh = *(aeq->shelftogh);
431 aeq->need_expose = true;
433 if (aeq->v_master != *(aeq->master)) {
434 aeq->v_master = *(aeq->master);
435 aeq->need_expose = true;
440 if (aeq->need_expose && aeq->queue_draw) {
441 aeq->need_expose = false;
442 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
450 eq_curve (Aeq* self, float f) {
451 float SR = self->srate;
452 double complex H = 1.0;
453 double theta = f * 2. * M_PI / SR;
454 double complex z = cexp(I * theta);
456 double m0, m1, m2, g, k;
460 if (self->v_filtog[0]) {
461 A = pow(10.0, self->v_g[0]/40.0);
462 m0 = self->v_filter[0].m[0];
463 m1 = self->v_filter[0].m[1];
464 m2 = self->v_filter[0].m[2];
465 g = self->v_filter[0].g;
466 k = self->v_filter[0].k;
467 if (self->v_shelftogl) {
469 H *= (A*m0*(z-1.0)*(z-1.0) + g*g*(m0+m2)*(1.0+z)*(1.0+z) + sqrt(A)*g*(k*m0+m1) * (z*z-1.0)) / (A*(z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z) + sqrt(A)*g*k*(z*z-1.0));
472 H *= ((z-1.0)*(z-1.0)) / ((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z) + g*k*(z*z-1.0));
478 if (self->v_filtog[1]) {
479 A = pow(10.0, self->v_g[1]/40.0);
480 m0 = self->v_filter[1].m[0];
481 m1 = self->v_filter[1].m[1];
482 m2 = self->v_filter[1].m[2];
483 g = self->v_filter[1].g;
484 k = self->v_filter[1].k;
485 H *= (g*k*m0*(z*z-1.0) + A*(g*(1.0+z)*(m1*(z-1.0) + g*m2*(1.0+z)) + m0*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)))) / (g*k*(z*z-1.0) + A*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)));
490 if (self->v_filtog[2]) {
491 A = pow(10.0, self->v_g[2]/40.0);
492 m0 = self->v_filter[2].m[0];
493 m1 = self->v_filter[2].m[1];
494 m2 = self->v_filter[2].m[2];
495 g = self->v_filter[2].g;
496 k = self->v_filter[2].k;
497 H *= (g*k*m0*(z*z-1.0) + A*(g*(1.0+z)*(m1*(z-1.0) + g*m2*(1.0+z)) + m0*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)))) / (g*k*(z*z-1.0) + A*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)));
502 if (self->v_filtog[3]) {
503 A = pow(10.0, self->v_g[3]/40.0);
504 m0 = self->v_filter[3].m[0];
505 m1 = self->v_filter[3].m[1];
506 m2 = self->v_filter[3].m[2];
507 g = self->v_filter[3].g;
508 k = self->v_filter[3].k;
509 H *= (g*k*m0*(z*z-1.0) + A*(g*(1.0+z)*(m1*(z-1.0) + g*m2*(1.0+z)) + m0*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)))) / (g*k*(z*z-1.0) + A*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)));
514 if (self->v_filtog[4]) {
515 A = pow(10.0, self->v_g[4]/40.0);
516 m0 = self->v_filter[4].m[0];
517 m1 = self->v_filter[4].m[1];
518 m2 = self->v_filter[4].m[2];
519 g = self->v_filter[4].g;
520 k = self->v_filter[4].k;
521 H *= (g*k*m0*(z*z-1.0) + A*(g*(1.0+z)*(m1*(z-1.0) + g*m2*(1.0+z)) + m0*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)))) / (g*k*(z*z-1.0) + A*((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z)));
526 if (self->v_filtog[5]) {
527 A = pow(10.0, self->v_g[5]/40.0);
528 m0 = self->v_filter[5].m[0];
529 m1 = self->v_filter[5].m[1];
530 m2 = self->v_filter[5].m[2];
531 g = self->v_filter[5].g;
532 k = self->v_filter[5].k;
533 if (self->v_shelftogh) {
535 H *= ( sqrt(A) * g * (1.0 + z) * (m1 * (z - 1.0) + sqrt(A)*g*m2*(1.0+z)) + m0 * ( (z-1.0)*(z-1.0) + A*g*g*(1.0+z)*(1.0+z) + sqrt(A)*g*k*(z*z-1.0))) / ((z-1.0)*(z-1.0) + A*g*g*(1.0+z)*(1.0+z) + sqrt(A)*g*k*(z*z-1.0));
538 H *= (g*g*(1.0+z)*(1.0+z)) / ((z-1.0)*(z-1.0) + g*g*(1.0+z)*(1.0+z) + g*k*(z*z-1.0));
546 static LV2_Inline_Display_Image_Surface *
547 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
549 Aeq* self = (Aeq*)instance;
550 uint32_t h = MIN (w, max_h);
552 if (!self->display || self->w != w || self->h != h) {
553 if (self->display) cairo_surface_destroy(self->display);
554 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
559 cairo_t* cr = cairo_create (self->display);
562 cairo_rectangle (cr, 0, 0, w, h);
563 cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
566 cairo_set_line_width(cr, 1.0);
568 // draw grid 5dB steps
569 const double dash2[] = {1, 3};
571 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
572 cairo_set_dash(cr, dash2, 2, 2);
573 cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
575 for (uint32_t d = 1; d < 8; ++d) {
576 const float y = -.5 + floorf (h * (d * 5.f / 40.f));
577 cairo_move_to (cr, 0, y);
578 cairo_line_to (cr, w, y);
585 cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
586 cairo_move_to (cr, 0, h);
588 for (uint32_t x = 0; x < w; ++x) {
589 // plot 20..20kHz +-20dB
590 const float x_hz = 20.f * powf (1000.f, (float)x / (float)w);
591 const float y_db = to_dB(eq_curve(self, x_hz)) + self->v_master;
592 const float y = h * -y_db / 40.0 + h / 2;
593 cairo_line_to (cr, x, y);
594 //printf("(hz,H,db)=(%f, %f, %f)\n", x_hz, from_dB(y_db), y_db);
596 cairo_stroke_preserve (cr);
598 cairo_line_to (cr, w, h);
599 cairo_close_path (cr);
602 // create RGBA surface
604 cairo_surface_flush (self->display);
605 self->surf.width = cairo_image_surface_get_width (self->display);
606 self->surf.height = cairo_image_surface_get_height (self->display);
607 self->surf.stride = cairo_image_surface_get_stride (self->display);
608 self->surf.data = cairo_image_surface_get_data (self->display);
615 extension_data(const char* uri)
618 static const LV2_Inline_Display_Interface display = { render_inline };
619 if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
627 cleanup(LV2_Handle instance)
630 Aeq* aeq = (Aeq*)instance;
632 cairo_surface_destroy (aeq->display);
638 static const LV2_Descriptor descriptor = {
650 const LV2_Descriptor*
651 lv2_descriptor(uint32_t index)