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];
117 LV2_Inline_Display_Image_Surface surf;
118 cairo_surface_t* display;
119 LV2_Inline_Display* queue_draw;
125 instantiate(const LV2_Descriptor* descriptor,
127 const char* bundle_path,
128 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 (i = 0; i < BANDS; i++)
143 linear_svf_reset(&aeq->v_filter[i]);
145 aeq->need_expose = true;
148 return (LV2_Handle)aeq;
152 connect_port(LV2_Handle instance,
156 Aeq* aeq = (Aeq*)instance;
158 switch ((PortIndex)port) {
160 aeq->shelftogl = (float*)data;
163 aeq->f0[0] = (float*)data;
166 aeq->g[0] = (float*)data;
169 aeq->f0[1] = (float*)data;
172 aeq->g[1] = (float*)data;
175 aeq->bw[1] = (float*)data;
178 aeq->f0[2] = (float*)data;
181 aeq->g[2] = (float*)data;
184 aeq->bw[2] = (float*)data;
187 aeq->f0[3] = (float*)data;
190 aeq->g[3] = (float*)data;
193 aeq->bw[3] = (float*)data;
196 aeq->f0[4] = (float*)data;
199 aeq->g[4] = (float*)data;
202 aeq->bw[4] = (float*)data;
205 aeq->shelftogh = (float*)data;
208 aeq->f0[5] = (float*)data;
211 aeq->g[5] = (float*)data;
214 aeq->master = (float*)data;
217 aeq->filtog[0] = (float*)data;
220 aeq->filtog[1] = (float*)data;
223 aeq->filtog[2] = (float*)data;
226 aeq->filtog[3] = (float*)data;
229 aeq->filtog[4] = (float*)data;
232 aeq->filtog[5] = (float*)data;
235 aeq->input = (float*)data;
238 aeq->output = (float*)data;
244 activate(LV2_Handle instance)
247 Aeq* aeq = (Aeq*)instance;
249 for (i = 0; i < BANDS; i++)
250 linear_svf_reset(&aeq->v_filter[i]);
254 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
256 static void linear_svf_set_hp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
258 double f0 = (double)cutoff;
259 double q = (double)resonance;
260 double sr = (double)sample_rate;
262 self->g = tan(M_PI * (f0 / sr));
265 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
266 self->a[1] = self->g * self->a[0];
267 self->a[2] = self->g * self->a[1];
270 self->m[1] = -self->k;
274 static void linear_svf_set_lp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
276 double f0 = (double)cutoff;
277 double q = (double)resonance;
278 double sr = (double)sample_rate;
280 self->g = tan(M_PI * (f0 / sr));
283 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
284 self->a[1] = self->g * self->a[0];
285 self->a[2] = self->g * self->a[1];
292 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
294 double f0 = (double)cutoff;
295 double q = (double)pow(2.0, 1.0 / bandwidth) / (pow(2.0, bandwidth) - 1.0);
296 double sr = (double)sample_rate;
297 double A = pow(10.0, gdb/40.0);
299 self->g = tan(M_PI * (f0 / sr));
300 self->k = 1.0 / (q * A);
302 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
303 self->a[1] = self->g * self->a[0];
304 self->a[2] = self->g * self->a[1];
307 self->m[1] = self->k * (A * A - 1.0);
311 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
313 double f0 = (double)cutoff;
314 double q = (double)resonance;
315 double sr = (double)sample_rate;
316 double A = pow(10.0, gdb/40.0);
318 self->g = tan(M_PI * (f0 / sr));
321 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
322 self->a[1] = self->g * self->a[0];
323 self->a[2] = self->g * self->a[1];
326 self->m[1] = self->k * (1.0 - A) * A;
327 self->m[2] = 1.0 - A * A;
330 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
332 double f0 = (double)cutoff;
333 double q = (double)resonance;
334 double sr = (double)sample_rate;
335 double A = pow(10.0, gdb/40.0);
337 self->g = tan(M_PI * (f0 / sr));
340 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
341 self->a[1] = self->g * self->a[0];
342 self->a[2] = self->g * self->a[1];
345 self->m[1] = self->k * (A - 1.0);
346 self->m[2] = A * A - 1.0;
349 static float run_linear_svf(struct linear_svf *self, float in)
352 double din = (double)in;
355 v[2] = din - self->s[1];
356 v[0] = (self->a[0] * self->s[0]) + (self->a[1] * v[2]);
357 v[1] = self->s[1] + (self->a[1] * self->s[0]) + (self->a[2] * v[2]);
359 self->s[0] = (2.0 * v[0]) - self->s[0];
360 self->s[1] = (2.0 * v[1]) - self->s[1];
362 out = (self->m[0] * din)
363 + (self->m[1] * v[0])
364 + (self->m[2] * v[1]);
370 run(LV2_Handle instance, uint32_t n_samples)
372 Aeq* aeq = (Aeq*)instance;
374 const float* const input = aeq->input;
375 float* const output = aeq->output;
377 float srate = aeq->srate;
381 if (*(aeq->shelftogl) > 0.5) {
382 linear_svf_set_lowshelf(&aeq->v_filter[0], *(aeq->g[0]), srate, *(aeq->f0[0]), 0.7071068);
384 linear_svf_set_hp(&aeq->v_filter[0], srate, *(aeq->f0[0]), 0.7071068);
386 linear_svf_set_peq(&aeq->v_filter[1], *(aeq->g[1]), srate, *(aeq->f0[1]), *(aeq->bw[1]));
387 linear_svf_set_peq(&aeq->v_filter[2], *(aeq->g[2]), srate, *(aeq->f0[2]), *(aeq->bw[2]));
388 linear_svf_set_peq(&aeq->v_filter[3], *(aeq->g[3]), srate, *(aeq->f0[3]), *(aeq->bw[3]));
389 linear_svf_set_peq(&aeq->v_filter[4], *(aeq->g[4]), srate, *(aeq->f0[4]), *(aeq->bw[4]));
391 if (*(aeq->shelftogh) > 0.5) {
392 linear_svf_set_highshelf(&aeq->v_filter[5], *(aeq->g[5]), srate, *(aeq->f0[5]), 0.7071068);
394 linear_svf_set_lp(&aeq->v_filter[5], srate, *(aeq->f0[5]), 0.7071068);
397 for (i = 0; i < n_samples; i++) {
400 for (j = 0; j < BANDS; j++) {
401 if (*(aeq->filtog[j]) > 0.5)
402 out = run_linear_svf(&aeq->v_filter[j], out);
404 output[i] = out * from_dB(*(aeq->master));
407 for (i = 0; i < BANDS; i++) {
408 if (aeq->v_f0[i] != *(aeq->f0[i])) {
409 aeq->v_f0[i] = *(aeq->f0[i]);
410 aeq->need_expose = true;
412 if (aeq->v_g[i] != *(aeq->g[i])) {
413 aeq->v_g[i] = *(aeq->g[i]);
414 aeq->need_expose = true;
416 if (i != 0 && i != 5 && aeq->v_bw[i] != *(aeq->bw[i])) {
417 aeq->v_bw[i] = *(aeq->bw[i]);
418 aeq->need_expose = true;
420 if (aeq->v_filtog[i] != *(aeq->filtog[i])) {
421 aeq->v_filtog[i] = *(aeq->filtog[i]);
422 aeq->need_expose = true;
424 if (aeq->v_shelftogl != *(aeq->shelftogl)) {
425 aeq->v_shelftogl = *(aeq->shelftogl);
426 aeq->need_expose = true;
428 if (aeq->v_shelftogh != *(aeq->shelftogh)) {
429 aeq->v_shelftogh = *(aeq->shelftogh);
430 aeq->need_expose = true;
435 if (aeq->need_expose && aeq->queue_draw) {
436 aeq->need_expose = false;
437 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
445 eq_curve (Aeq* self, float f) {
446 float SR = self->srate;
447 double complex H = 1.0;
448 double theta = f * 2. * M_PI / SR;
449 double complex z = cexp(I * theta);
451 double m0, m1, m2, g, k;
455 if (self->v_filtog[0]) {
456 A = pow(10.0, self->v_g[0]/40.0);
457 m0 = self->v_filter[0].m[0];
458 m1 = self->v_filter[0].m[1];
459 m2 = self->v_filter[0].m[2];
460 g = self->v_filter[0].g;
461 k = self->v_filter[0].k;
462 if (self->v_shelftogl) {
464 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));
467 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));
473 if (self->v_filtog[1]) {
474 A = pow(10.0, self->v_g[1]/40.0);
475 m0 = self->v_filter[1].m[0];
476 m1 = self->v_filter[1].m[1];
477 m2 = self->v_filter[1].m[2];
478 g = self->v_filter[1].g;
479 k = self->v_filter[1].k;
480 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)));
485 if (self->v_filtog[2]) {
486 A = pow(10.0, self->v_g[2]/40.0);
487 m0 = self->v_filter[2].m[0];
488 m1 = self->v_filter[2].m[1];
489 m2 = self->v_filter[2].m[2];
490 g = self->v_filter[2].g;
491 k = self->v_filter[2].k;
492 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)));
497 if (self->v_filtog[3]) {
498 A = pow(10.0, self->v_g[3]/40.0);
499 m0 = self->v_filter[3].m[0];
500 m1 = self->v_filter[3].m[1];
501 m2 = self->v_filter[3].m[2];
502 g = self->v_filter[3].g;
503 k = self->v_filter[3].k;
504 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)));
509 if (self->v_filtog[4]) {
510 A = pow(10.0, self->v_g[4]/40.0);
511 m0 = self->v_filter[4].m[0];
512 m1 = self->v_filter[4].m[1];
513 m2 = self->v_filter[4].m[2];
514 g = self->v_filter[4].g;
515 k = self->v_filter[4].k;
516 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)));
521 if (self->v_filtog[5]) {
522 A = pow(10.0, self->v_g[5]/40.0);
523 m0 = self->v_filter[5].m[0];
524 m1 = self->v_filter[5].m[1];
525 m2 = self->v_filter[5].m[2];
526 g = self->v_filter[5].g;
527 k = self->v_filter[5].k;
528 if (self->v_shelftogh) {
530 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));
533 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));
541 static LV2_Inline_Display_Image_Surface *
542 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
544 Aeq* self = (Aeq*)instance;
545 uint32_t h = MIN (w, max_h);
547 if (!self->display || self->w != w || self->h != h) {
548 if (self->display) cairo_surface_destroy(self->display);
549 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
554 cairo_t* cr = cairo_create (self->display);
557 cairo_rectangle (cr, 0, 0, w, h);
558 cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
561 cairo_set_line_width(cr, 1.0);
563 // draw grid 10dB steps
564 const double dash2[] = {1, 3};
566 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
567 cairo_set_dash(cr, dash2, 2, 2);
568 cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
570 for (uint32_t d = 1; d < 6; ++d) {
571 const float y = -.5 + floorf (h * (d * 10.f / 60.f));
572 cairo_move_to (cr, 0, y);
573 cairo_line_to (cr, w, y);
580 cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
581 cairo_move_to (cr, 0, h);
583 for (uint32_t x = 0; x < w; ++x) {
584 // plot 20..20kHz +-30dB
585 const float x_hz = 20.f * powf (1000.f, (float)x / (float)w);
586 const float y_db = to_dB(eq_curve(self, x_hz));
587 const float y = h * -y_db / 60.0 + h / 2;
588 cairo_line_to (cr, x, y);
589 printf("(hz,H,db)=(%f, %f, %f)\n", x_hz, from_dB(y_db), y_db);
591 cairo_stroke_preserve (cr);
593 cairo_line_to (cr, w, h);
594 cairo_close_path (cr);
597 // create RGBA surface
599 cairo_surface_flush (self->display);
600 self->surf.width = cairo_image_surface_get_width (self->display);
601 self->surf.height = cairo_image_surface_get_height (self->display);
602 self->surf.stride = cairo_image_surface_get_stride (self->display);
603 self->surf.data = cairo_image_surface_get_data (self->display);
610 extension_data(const char* uri)
613 static const LV2_Inline_Display_Interface display = { render_inline };
614 if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
622 cleanup(LV2_Handle instance)
625 Aeq* aeq = (Aeq*)instance;
627 cairo_surface_destroy (aeq->display);
633 static const LV2_Descriptor descriptor = {
645 const LV2_Descriptor*
646 lv2_descriptor(uint32_t index)