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)
131 Aeq* aeq = (Aeq*)malloc(sizeof(Aeq));
135 for (int i=0; features[i]; ++i) {
136 if (!strcmp(features[i]->URI, LV2_INLINEDISPLAY__queue_draw)) {
137 aeq->queue_draw = (LV2_Inline_Display*) features[i]->data;
142 for (int i = 0; i < BANDS; i++)
143 linear_svf_reset(&aeq->v_filter[i]);
145 aeq->need_expose = true;
150 return (LV2_Handle)aeq;
154 connect_port(LV2_Handle instance,
158 Aeq* aeq = (Aeq*)instance;
160 switch ((PortIndex)port) {
162 aeq->shelftogl = (float*)data;
165 aeq->f0[0] = (float*)data;
168 aeq->g[0] = (float*)data;
171 aeq->f0[1] = (float*)data;
174 aeq->g[1] = (float*)data;
177 aeq->bw[1] = (float*)data;
180 aeq->f0[2] = (float*)data;
183 aeq->g[2] = (float*)data;
186 aeq->bw[2] = (float*)data;
189 aeq->f0[3] = (float*)data;
192 aeq->g[3] = (float*)data;
195 aeq->bw[3] = (float*)data;
198 aeq->f0[4] = (float*)data;
201 aeq->g[4] = (float*)data;
204 aeq->bw[4] = (float*)data;
207 aeq->shelftogh = (float*)data;
210 aeq->f0[5] = (float*)data;
213 aeq->g[5] = (float*)data;
216 aeq->master = (float*)data;
219 aeq->filtog[0] = (float*)data;
222 aeq->filtog[1] = (float*)data;
225 aeq->filtog[2] = (float*)data;
228 aeq->filtog[3] = (float*)data;
231 aeq->filtog[4] = (float*)data;
234 aeq->filtog[5] = (float*)data;
237 aeq->input = (float*)data;
240 aeq->output = (float*)data;
246 activate(LV2_Handle instance)
249 Aeq* aeq = (Aeq*)instance;
251 for (i = 0; i < BANDS; i++)
252 linear_svf_reset(&aeq->v_filter[i]);
256 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
258 static void linear_svf_set_hp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
260 double f0 = (double)cutoff;
261 double q = (double)resonance;
262 double sr = (double)sample_rate;
264 self->g = tan(M_PI * (f0 / sr));
267 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
268 self->a[1] = self->g * self->a[0];
269 self->a[2] = self->g * self->a[1];
272 self->m[1] = -self->k;
276 static void linear_svf_set_lp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
278 double f0 = (double)cutoff;
279 double q = (double)resonance;
280 double sr = (double)sample_rate;
282 self->g = tan(M_PI * (f0 / sr));
285 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
286 self->a[1] = self->g * self->a[0];
287 self->a[2] = self->g * self->a[1];
294 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
296 double f0 = (double)cutoff;
297 double q = (double)pow(2.0, 1.0 / bandwidth) / (pow(2.0, bandwidth) - 1.0);
298 double sr = (double)sample_rate;
299 double A = pow(10.0, gdb/40.0);
301 self->g = tan(M_PI * (f0 / sr));
302 self->k = 1.0 / (q * A);
304 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
305 self->a[1] = self->g * self->a[0];
306 self->a[2] = self->g * self->a[1];
309 self->m[1] = self->k * (A * A - 1.0);
313 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
315 double f0 = (double)cutoff;
316 double q = (double)resonance;
317 double sr = (double)sample_rate;
318 double A = pow(10.0, gdb/40.0);
320 self->g = tan(M_PI * (f0 / sr));
323 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
324 self->a[1] = self->g * self->a[0];
325 self->a[2] = self->g * self->a[1];
328 self->m[1] = self->k * (1.0 - A) * A;
329 self->m[2] = 1.0 - A * A;
332 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
334 double f0 = (double)cutoff;
335 double q = (double)resonance;
336 double sr = (double)sample_rate;
337 double A = pow(10.0, gdb/40.0);
339 self->g = tan(M_PI * (f0 / sr));
342 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
343 self->a[1] = self->g * self->a[0];
344 self->a[2] = self->g * self->a[1];
347 self->m[1] = self->k * (A - 1.0);
348 self->m[2] = A * A - 1.0;
351 static float run_linear_svf(struct linear_svf *self, float in)
354 double din = (double)in;
357 v[2] = din - self->s[1];
358 v[0] = (self->a[0] * self->s[0]) + (self->a[1] * v[2]);
359 v[1] = self->s[1] + (self->a[1] * self->s[0]) + (self->a[2] * v[2]);
361 self->s[0] = (2.0 * v[0]) - self->s[0];
362 self->s[1] = (2.0 * v[1]) - self->s[1];
364 out = (self->m[0] * din)
365 + (self->m[1] * v[0])
366 + (self->m[2] * v[1]);
372 run(LV2_Handle instance, uint32_t n_samples)
374 Aeq* aeq = (Aeq*)instance;
376 const float* const input = aeq->input;
377 float* const output = aeq->output;
379 float srate = aeq->srate;
383 if (*(aeq->shelftogl) > 0.5) {
384 linear_svf_set_lowshelf(&aeq->v_filter[0], *(aeq->g[0]), srate, *(aeq->f0[0]), 0.7071068);
386 linear_svf_set_hp(&aeq->v_filter[0], srate, *(aeq->f0[0]), 0.7071068);
388 linear_svf_set_peq(&aeq->v_filter[1], *(aeq->g[1]), srate, *(aeq->f0[1]), *(aeq->bw[1]));
389 linear_svf_set_peq(&aeq->v_filter[2], *(aeq->g[2]), srate, *(aeq->f0[2]), *(aeq->bw[2]));
390 linear_svf_set_peq(&aeq->v_filter[3], *(aeq->g[3]), srate, *(aeq->f0[3]), *(aeq->bw[3]));
391 linear_svf_set_peq(&aeq->v_filter[4], *(aeq->g[4]), srate, *(aeq->f0[4]), *(aeq->bw[4]));
393 if (*(aeq->shelftogh) > 0.5) {
394 linear_svf_set_highshelf(&aeq->v_filter[5], *(aeq->g[5]), srate, *(aeq->f0[5]), 0.7071068);
396 linear_svf_set_lp(&aeq->v_filter[5], srate, *(aeq->f0[5]), 0.7071068);
399 for (i = 0; i < n_samples; i++) {
402 for (j = 0; j < BANDS; j++) {
403 if (*(aeq->filtog[j]) > 0.5)
404 out = run_linear_svf(&aeq->v_filter[j], out);
406 output[i] = out * from_dB(*(aeq->master));
409 for (i = 0; i < BANDS; i++) {
410 if (aeq->v_f0[i] != *(aeq->f0[i])) {
411 aeq->v_f0[i] = *(aeq->f0[i]);
412 aeq->need_expose = true;
414 if (aeq->v_g[i] != *(aeq->g[i])) {
415 aeq->v_g[i] = *(aeq->g[i]);
416 aeq->need_expose = true;
418 if (i != 0 && i != 5 && aeq->v_bw[i] != *(aeq->bw[i])) {
419 aeq->v_bw[i] = *(aeq->bw[i]);
420 aeq->need_expose = true;
422 if (aeq->v_filtog[i] != *(aeq->filtog[i])) {
423 aeq->v_filtog[i] = *(aeq->filtog[i]);
424 aeq->need_expose = true;
426 if (aeq->v_shelftogl != *(aeq->shelftogl)) {
427 aeq->v_shelftogl = *(aeq->shelftogl);
428 aeq->need_expose = true;
430 if (aeq->v_shelftogh != *(aeq->shelftogh)) {
431 aeq->v_shelftogh = *(aeq->shelftogh);
432 aeq->need_expose = true;
434 if (aeq->v_master != *(aeq->master)) {
435 aeq->v_master = *(aeq->master);
436 aeq->need_expose = true;
441 if (aeq->need_expose && aeq->queue_draw) {
442 aeq->need_expose = false;
443 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
451 eq_curve (Aeq* self, float f) {
452 float SR = self->srate;
453 double complex H = 1.0;
454 double theta = f * 2. * M_PI / SR;
455 double complex z = cexp(I * theta);
457 double m0, m1, m2, g, k;
461 if (self->v_filtog[0]) {
462 A = pow(10.0, self->v_g[0]/40.0);
463 m0 = self->v_filter[0].m[0];
464 m1 = self->v_filter[0].m[1];
465 m2 = self->v_filter[0].m[2];
466 g = self->v_filter[0].g;
467 k = self->v_filter[0].k;
468 if (self->v_shelftogl) {
470 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));
473 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));
479 if (self->v_filtog[1]) {
480 A = pow(10.0, self->v_g[1]/40.0);
481 m0 = self->v_filter[1].m[0];
482 m1 = self->v_filter[1].m[1];
483 m2 = self->v_filter[1].m[2];
484 g = self->v_filter[1].g;
485 k = self->v_filter[1].k;
486 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)));
491 if (self->v_filtog[2]) {
492 A = pow(10.0, self->v_g[2]/40.0);
493 m0 = self->v_filter[2].m[0];
494 m1 = self->v_filter[2].m[1];
495 m2 = self->v_filter[2].m[2];
496 g = self->v_filter[2].g;
497 k = self->v_filter[2].k;
498 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)));
503 if (self->v_filtog[3]) {
504 A = pow(10.0, self->v_g[3]/40.0);
505 m0 = self->v_filter[3].m[0];
506 m1 = self->v_filter[3].m[1];
507 m2 = self->v_filter[3].m[2];
508 g = self->v_filter[3].g;
509 k = self->v_filter[3].k;
510 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)));
515 if (self->v_filtog[4]) {
516 A = pow(10.0, self->v_g[4]/40.0);
517 m0 = self->v_filter[4].m[0];
518 m1 = self->v_filter[4].m[1];
519 m2 = self->v_filter[4].m[2];
520 g = self->v_filter[4].g;
521 k = self->v_filter[4].k;
522 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)));
527 if (self->v_filtog[5]) {
528 A = pow(10.0, self->v_g[5]/40.0);
529 m0 = self->v_filter[5].m[0];
530 m1 = self->v_filter[5].m[1];
531 m2 = self->v_filter[5].m[2];
532 g = self->v_filter[5].g;
533 k = self->v_filter[5].k;
534 if (self->v_shelftogh) {
536 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));
539 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));
547 static LV2_Inline_Display_Image_Surface *
548 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
550 Aeq* self = (Aeq*)instance;
551 uint32_t h = MIN (w * 9 / 16, max_h);
553 if (!self->display || self->w != w || self->h != h) {
554 if (self->display) cairo_surface_destroy(self->display);
555 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
560 cairo_t* cr = cairo_create (self->display);
563 cairo_rectangle (cr, 0, 0, w, h);
564 cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
567 cairo_set_line_width(cr, 1.0);
569 // draw grid 5dB steps
570 const double dash2[] = {1, 3};
572 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
573 cairo_set_dash(cr, dash2, 2, 2);
574 cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
576 for (uint32_t d = 1; d < 8; ++d) {
577 const float y = -.5 + floorf (h * (d * 5.f / 40.f));
578 cairo_move_to (cr, 0, y);
579 cairo_line_to (cr, w, y);
586 cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
587 cairo_move_to (cr, 0, h);
589 for (uint32_t x = 0; x < w; ++x) {
590 // plot 20..20kHz +-20dB
591 const float x_hz = 20.f * powf (1000.f, (float)x / (float)w);
592 const float y_db = to_dB(eq_curve(self, x_hz)) + self->v_master;
593 const float y = h * -y_db / 40.0 + h / 2;
594 cairo_line_to (cr, x, y);
595 //printf("(hz,H,db)=(%f, %f, %f)\n", x_hz, from_dB(y_db), y_db);
597 cairo_stroke_preserve (cr);
599 cairo_line_to (cr, w, h);
600 cairo_close_path (cr);
603 // create RGBA surface
605 cairo_surface_flush (self->display);
606 self->surf.width = cairo_image_surface_get_width (self->display);
607 self->surf.height = cairo_image_surface_get_height (self->display);
608 self->surf.stride = cairo_image_surface_get_stride (self->display);
609 self->surf.data = cairo_image_surface_get_data (self->display);
616 extension_data(const char* uri)
619 static const LV2_Inline_Display_Interface display = { render_inline };
620 if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
628 cleanup(LV2_Handle instance)
631 Aeq* aeq = (Aeq*)instance;
633 cairo_surface_destroy (aeq->display);
639 static const LV2_Descriptor descriptor = {
651 const LV2_Descriptor*
652 lv2_descriptor(uint32_t index)