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"
38 #define MIN(A,B) ((A) < (B)) ? (A) : (B)
71 return (20.0*log10(g));
76 return (exp(gdb/20.0*log(10.0)));
80 is_eq(float a, float b) {
81 return (fabsf(a - b) < SMALL);
91 static void linear_svf_reset(struct linear_svf *self)
93 self->s[0] = self->s[1] = 0.0;
100 float* filtog[BANDS];
108 struct linear_svf v_filter[BANDS];
112 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*)calloc(1, 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->f0[0] = (float*)data;
165 aeq->g[0] = (float*)data;
168 aeq->f0[1] = (float*)data;
171 aeq->g[1] = (float*)data;
174 aeq->bw[1] = (float*)data;
177 aeq->f0[2] = (float*)data;
180 aeq->g[2] = (float*)data;
183 aeq->bw[2] = (float*)data;
186 aeq->f0[3] = (float*)data;
189 aeq->g[3] = (float*)data;
192 aeq->bw[3] = (float*)data;
195 aeq->f0[4] = (float*)data;
198 aeq->g[4] = (float*)data;
201 aeq->bw[4] = (float*)data;
204 aeq->f0[5] = (float*)data;
207 aeq->g[5] = (float*)data;
210 aeq->master = (float*)data;
213 aeq->filtog[0] = (float*)data;
216 aeq->filtog[1] = (float*)data;
219 aeq->filtog[2] = (float*)data;
222 aeq->filtog[3] = (float*)data;
225 aeq->filtog[4] = (float*)data;
228 aeq->filtog[5] = (float*)data;
231 aeq->input = (float*)data;
234 aeq->output = (float*)data;
240 activate(LV2_Handle instance)
243 Aeq* aeq = (Aeq*)instance;
245 for (i = 0; i < BANDS; i++)
246 linear_svf_reset(&aeq->v_filter[i]);
250 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
252 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
254 double f0 = (double)cutoff;
255 double q = (double)pow(2.0, 1.0 / bandwidth) / (pow(2.0, bandwidth) - 1.0);
256 double sr = (double)sample_rate;
257 double A = pow(10.0, gdb/40.0);
259 self->g = tan(M_PI * (f0 / sr));
260 self->k = 1.0 / (q * A);
262 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
263 self->a[1] = self->g * self->a[0];
264 self->a[2] = self->g * self->a[1];
267 self->m[1] = self->k * (A * A - 1.0);
271 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
273 double f0 = (double)cutoff;
274 double q = (double)resonance;
275 double sr = (double)sample_rate;
276 double A = pow(10.0, gdb/40.0);
278 self->g = tan(M_PI * (f0 / sr));
281 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
282 self->a[1] = self->g * self->a[0];
283 self->a[2] = self->g * self->a[1];
286 self->m[1] = self->k * (1.0 - A) * A;
287 self->m[2] = 1.0 - A * A;
290 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
292 double f0 = (double)cutoff;
293 double q = (double)resonance;
294 double sr = (double)sample_rate;
295 double A = pow(10.0, gdb/40.0);
297 self->g = tan(M_PI * (f0 / sr));
300 self->a[0] = 1.0 / (1.0 + self->g * (self->g + self->k));
301 self->a[1] = self->g * self->a[0];
302 self->a[2] = self->g * self->a[1];
305 self->m[1] = self->k * (A - 1.0);
306 self->m[2] = A * A - 1.0;
309 static float run_linear_svf(struct linear_svf *self, float in)
312 double din = (double)in;
315 v[2] = din - self->s[1];
316 v[0] = (self->a[0] * self->s[0]) + (self->a[1] * v[2]);
317 v[1] = self->s[1] + (self->a[1] * self->s[0]) + (self->a[2] * v[2]);
319 self->s[0] = (2.0 * v[0]) - self->s[0];
320 self->s[1] = (2.0 * v[1]) - self->s[1];
322 out = (self->m[0] * din)
323 + (self->m[1] * v[0])
324 + (self->m[2] * v[1]);
329 static void set_params(LV2_Handle instance, int band) {
330 Aeq* aeq = (Aeq*)instance;
334 linear_svf_set_lowshelf(&aeq->v_filter[0], aeq->v_g[0], aeq->srate, aeq->v_f0[0], 0.7071068);
340 linear_svf_set_peq(&aeq->v_filter[band], aeq->v_g[band], aeq->srate, aeq->v_f0[band], aeq->v_bw[band]);
343 linear_svf_set_highshelf(&aeq->v_filter[5], aeq->v_g[5], aeq->srate, aeq->v_f0[5], 0.7071068);
349 run(LV2_Handle instance, uint32_t n_samples)
351 Aeq* aeq = (Aeq*)instance;
353 const float* const input = aeq->input;
354 float* const output = aeq->output;
359 // 15Hz time constant
360 const float tau = (1.0 - exp(-2.0 * M_PI * n_samples * 15. / aeq->srate));
362 for (i = 0; i < n_samples; i++) {
365 for (j = 0; j < BANDS; j++) {
366 out = run_linear_svf(&aeq->v_filter[j], out);
368 output[i] = out * from_dB(*(aeq->master));
371 for (i = 0; i < BANDS; i++) {
372 if (!is_eq(aeq->v_filtog[i], *aeq->filtog[i])) {
373 aeq->v_filtog[i] = *(aeq->filtog[i]);
375 if (!is_eq(aeq->v_f0[i], *aeq->f0[i])) {
376 aeq->v_f0[i] += tau * (*aeq->f0[i] - aeq->v_f0[i]);
377 aeq->need_expose = true;
379 if (aeq->v_filtog[i] < 0.5) {
380 if (!is_eq(aeq->v_g[i], 0.f)) {
381 aeq->v_g[i] += tau * (0.0 - aeq->v_g[i]);
382 aeq->need_expose = true;
384 } else if (aeq->v_filtog[i] >= 0.5) {
385 if (!is_eq(aeq->v_g[i], *aeq->g[i])) {
386 aeq->v_g[i] += tau * (*aeq->g[i] - aeq->v_g[i]);
387 aeq->need_expose = true;
390 if (i != 0 && i != 5 && !is_eq(aeq->v_bw[i], *aeq->bw[i])) {
391 aeq->v_bw[i] += tau * (*aeq->bw[i] - aeq->v_bw[i]);
392 aeq->need_expose = true;
394 if (!is_eq(aeq->v_master, *aeq->master)) {
395 aeq->v_master = *(aeq->master);
396 aeq->need_expose = true;
398 if (aeq->need_expose == true) {
404 if (aeq->need_expose && aeq->queue_draw) {
405 aeq->need_expose = false;
406 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
412 calc_peq(Aeq* self, int i, double omega) {
413 double complex H = 0.0;
414 double complex z = cexp(I * omega);
415 double complex zz = cexp(2. * I * omega);
416 double complex zm = z - 1.0;
417 double complex zp = z + 1.0;
418 double complex zzm = zz - 1.0;
420 double A = pow(10.0, self->v_g[i]/40.0);
421 double g = self->v_filter[i].g;
422 double k = self->v_filter[i].k * A;
423 double m1 = k * (A * A - 1.0) / A;
425 H = (g*k*zzm + A*(g*zp*(m1*zm) + (zm*zm + g*g*zp*zp))) / (g*k*zzm + A*(zm*zm + g*g*zp*zp));
430 calc_lowshelf(Aeq* self, double omega) {
431 double complex H = 0.0;
432 double complex z = cexp(I * omega);
433 double complex zz = cexp(2. * I * omega);
434 double complex zm = z - 1.0;
435 double complex zp = z + 1.0;
436 double complex zzm = zz - 1.0;
438 double A = pow(10.0, self->v_g[0]/40.0);
439 double g = self->v_filter[0].g;
440 double k = self->v_filter[0].k;
441 double m0 = self->v_filter[0].m[0];
442 double m1 = self->v_filter[0].m[1];
443 double m2 = self->v_filter[0].m[2];
445 H = (A*m0*zm*zm + g*g*(m0+m2)*zp*zp + sqrt(A)*g*(k*m0+m1) * zzm) / (A*zm*zm + g*g*zp*zp + sqrt(A)*g*k*zzm);
450 calc_highshelf(Aeq* self, double omega) {
451 double complex H = 0.0;
452 double complex z = cexp(I * omega);
453 double complex zz = cexp(2. * I * omega);
454 double complex zm = z - 1.0;
455 double complex zp = z + 1.0;
456 double complex zzm = zz - 1.0;
458 double A = pow(10.0, self->v_g[5]/40.0);
459 double g = self->v_filter[5].g;
460 double k = self->v_filter[5].k;
461 double m0 = self->v_filter[5].m[0];
462 double m1 = self->v_filter[5].m[1];
463 double m2 = self->v_filter[5].m[2];
465 H = ( sqrt(A) * g * zp * (m1 * zm + sqrt(A)*g*m2*zp) + m0 * ( zm*zm + A*g*g*zp*zp + sqrt(A)*g*k*zzm)) / (zm*zm + A*g*g*zp*zp + sqrt(A)*g*k*zzm);
471 eq_curve (Aeq* self, float f) {
472 double response = 1.0;
473 double SR = (double)self->srate;
474 double omega = f * 2. * M_PI / SR;
477 response *= calc_lowshelf(self, omega);
480 response *= calc_peq(self, 1, omega);
481 response *= calc_peq(self, 2, omega);
482 response *= calc_peq(self, 3, omega);
483 response *= calc_peq(self, 4, omega);
486 response *= calc_highshelf(self, omega);
488 return (float)response;
491 static LV2_Inline_Display_Image_Surface *
492 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
494 Aeq* self = (Aeq*)instance;
495 uint32_t h = MIN (1 | (uint32_t)ceilf (w * 9.f / 16.f), max_h);
497 if (!self->display || self->w != w || self->h != h) {
498 if (self->display) cairo_surface_destroy(self->display);
499 self->display = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
504 cairo_t* cr = cairo_create (self->display);
507 cairo_rectangle (cr, 0, 0, w, h);
508 cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
511 cairo_set_line_width(cr, 1.0);
513 // prepare grid drawing
515 const double dash2[] = {1, 3};
516 //cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
517 cairo_set_dash(cr, dash2, 2, 2);
518 cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
520 // draw x-grid 6dB steps
521 for (int32_t d = -18; d <= 18; d+=6) {
522 float y = (float)h * (d / 40.0 + 0.5);
524 cairo_move_to (cr, 0, y);
525 cairo_line_to (cr, w, y);
528 // draw y-axis grid 100, 1k, 10K
529 for (int32_t f = 100; f <= 10000; f *= 10) {
530 float x = w * log10 (f / 20.0) / log10 (1000.0);
532 cairo_move_to (cr, x, 0);
533 cairo_line_to (cr, x, h);
541 cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
542 cairo_move_to (cr, 0, h);
544 for (uint32_t x = 0; x < w; ++x) {
545 // plot 20..20kHz +-20dB
546 const float x_hz = 20.f * powf (1000.f, (float)x / (float)w);
547 const float y_db = to_dB(eq_curve(self, x_hz)) + self->v_master;
548 const float y = (float)h * (-y_db / 40.0 + 0.5);
549 cairo_line_to (cr, x, y);
551 cairo_stroke_preserve (cr);
553 cairo_line_to (cr, w, h);
554 cairo_close_path (cr);
557 // create RGBA surface
559 cairo_surface_flush (self->display);
560 self->surf.width = cairo_image_surface_get_width (self->display);
561 self->surf.height = cairo_image_surface_get_height (self->display);
562 self->surf.stride = cairo_image_surface_get_stride (self->display);
563 self->surf.data = cairo_image_surface_get_data (self->display);
570 extension_data(const char* uri)
573 static const LV2_Inline_Display_Interface display = { render_inline };
574 if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
582 cleanup(LV2_Handle instance)
585 Aeq* aeq = (Aeq*)instance;
587 cairo_surface_destroy (aeq->display);
593 static const LV2_Descriptor descriptor = {
605 const LV2_Descriptor*
606 lv2_descriptor(uint32_t index)