a-EQ: Tweak default values and inline display scale +-20dB
[ardour.git] / libs / plugins / a-eq.lv2 / a-eq.c
1 /* a-eq
2  * Copyright (C) 2016 Damien Zammit <damien@zamaudio.com>
3  *
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.
8  *
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.
13  */
14
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE // needed for M_PI
17 #endif
18
19 #include <math.h>
20 #include <complex.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25
26 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
27
28 #ifdef LV2_EXTENDED
29 #include <cairo/cairo.h>
30 #include "ardour/lv2_extensions.h"
31 #endif
32
33 #define AEQ_URI "urn:ardour:a-eq"
34 #define BANDS   6
35
36 #ifndef MIN
37 #define MIN(A,B) ((A) < (B)) ? (A) : (B)
38 #endif
39
40 typedef enum {
41         AEQ_SHELFTOGL = 0,
42         AEQ_FREQL,
43         AEQ_GAINL,
44         AEQ_FREQ1,
45         AEQ_GAIN1,
46         AEQ_BW1,
47         AEQ_FREQ2,
48         AEQ_GAIN2,
49         AEQ_BW2,
50         AEQ_FREQ3,
51         AEQ_GAIN3,
52         AEQ_BW3,
53         AEQ_FREQ4,
54         AEQ_GAIN4,
55         AEQ_BW4,
56         AEQ_SHELFTOGH,
57         AEQ_FREQH,
58         AEQ_GAINH,
59         AEQ_MASTER,
60         AEQ_FILTOGL,
61         AEQ_FILTOG1,
62         AEQ_FILTOG2,
63         AEQ_FILTOG3,
64         AEQ_FILTOG4,
65         AEQ_FILTOGH,
66         AEQ_INPUT,
67         AEQ_OUTPUT,
68 } PortIndex;
69
70 static inline float
71 to_dB(float g) {
72         return (20.f*log10(g));
73 }
74
75 static inline float
76 from_dB(float gdb) {
77         return (exp(gdb/20.f*log(10.f)));
78 }
79
80 struct linear_svf {
81         double g, k;
82         double a[3];
83         double m[3];
84         double s[2];
85 };
86
87 static void linear_svf_reset(struct linear_svf *self)
88 {
89         self->s[0] = self->s[1] = 0.0;
90 }
91
92 typedef struct {
93         float* shelftogl;
94         float* shelftogh;
95         float* f0[BANDS];
96         float* g[BANDS];
97         float* bw[BANDS];
98         float* filtog[BANDS];
99         float* master;
100
101         float srate;
102
103         float* input;
104         float* output;
105
106         struct linear_svf v_filter[BANDS];
107         float v_g[BANDS];
108         float v_bw[BANDS];
109         float v_f0[BANDS];
110         float v_filtog[BANDS];
111         float v_shelftogl;
112         float v_shelftogh;
113         float v_master;
114
115         bool need_expose;
116
117 #ifdef LV2_EXTENDED
118         LV2_Inline_Display_Image_Surface surf;
119         cairo_surface_t*                 display;
120         LV2_Inline_Display*              queue_draw;
121         uint32_t                         w, h;
122 #endif
123 } Aeq;
124
125 static LV2_Handle
126 instantiate(const LV2_Descriptor* descriptor,
127             double rate,
128             const char* bundle_path,
129             const LV2_Feature* const* features)
130 {
131         int i;
132         Aeq* aeq = (Aeq*)malloc(sizeof(Aeq));
133         aeq->srate = rate;
134         
135 #ifdef LV2_EXTENDED
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;
139                 }
140         }
141 #endif
142
143         for (i = 0; i < BANDS; i++)
144                 linear_svf_reset(&aeq->v_filter[i]);
145
146         aeq->need_expose = true;
147         aeq->display = NULL;
148
149         return (LV2_Handle)aeq;
150 }
151
152 static void
153 connect_port(LV2_Handle instance,
154              uint32_t port,
155              void* data)
156 {
157         Aeq* aeq = (Aeq*)instance;
158
159         switch ((PortIndex)port) {
160         case AEQ_SHELFTOGL:
161                 aeq->shelftogl = (float*)data;
162                 break;
163         case AEQ_FREQL:
164                 aeq->f0[0] = (float*)data;
165                 break;
166         case AEQ_GAINL:
167                 aeq->g[0] = (float*)data;
168                 break;
169         case AEQ_FREQ1:
170                 aeq->f0[1] = (float*)data;
171                 break;
172         case AEQ_GAIN1:
173                 aeq->g[1] = (float*)data;
174                 break;
175         case AEQ_BW1:
176                 aeq->bw[1] = (float*)data;
177                 break;
178         case AEQ_FREQ2:
179                 aeq->f0[2] = (float*)data;
180                 break;
181         case AEQ_GAIN2:
182                 aeq->g[2] = (float*)data;
183                 break;
184         case AEQ_BW2:
185                 aeq->bw[2] = (float*)data;
186                 break;
187         case AEQ_FREQ3:
188                 aeq->f0[3] = (float*)data;
189                 break;
190         case AEQ_GAIN3:
191                 aeq->g[3] = (float*)data;
192                 break;
193         case AEQ_BW3:
194                 aeq->bw[3] = (float*)data;
195                 break;
196         case AEQ_FREQ4:
197                 aeq->f0[4] = (float*)data;
198                 break;
199         case AEQ_GAIN4:
200                 aeq->g[4] = (float*)data;
201                 break;
202         case AEQ_BW4:
203                 aeq->bw[4] = (float*)data;
204                 break;
205         case AEQ_SHELFTOGH:
206                 aeq->shelftogh = (float*)data;
207                 break;
208         case AEQ_FREQH:
209                 aeq->f0[5] = (float*)data;
210                 break;
211         case AEQ_GAINH:
212                 aeq->g[5] = (float*)data;
213                 break;
214         case AEQ_MASTER:
215                 aeq->master = (float*)data;
216                 break;
217         case AEQ_FILTOGL:
218                 aeq->filtog[0] = (float*)data;
219                 break;
220         case AEQ_FILTOG1:
221                 aeq->filtog[1] = (float*)data;
222                 break;
223         case AEQ_FILTOG2:
224                 aeq->filtog[2] = (float*)data;
225                 break;
226         case AEQ_FILTOG3:
227                 aeq->filtog[3] = (float*)data;
228                 break;
229         case AEQ_FILTOG4:
230                 aeq->filtog[4] = (float*)data;
231                 break;
232         case AEQ_FILTOGH:
233                 aeq->filtog[5] = (float*)data;
234                 break;
235         case AEQ_INPUT:
236                 aeq->input = (float*)data;
237                 break;
238         case AEQ_OUTPUT:
239                 aeq->output = (float*)data;
240                 break;
241         }
242 }
243
244 static void
245 activate(LV2_Handle instance)
246 {
247         int i;
248         Aeq* aeq = (Aeq*)instance;
249
250         for (i = 0; i < BANDS; i++)
251                 linear_svf_reset(&aeq->v_filter[i]);
252 }
253
254 // SVF filters
255 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
256
257 static void linear_svf_set_hp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
258 {
259         double f0 = (double)cutoff;
260         double q = (double)resonance;
261         double sr = (double)sample_rate;
262
263         self->g = tan(M_PI * (f0 / sr));
264         self->k = 1.0 / q;
265
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];
269
270         self->m[0] = 1.0;
271         self->m[1] = -self->k;
272         self->m[2] = -1.0;
273 }
274
275 static void linear_svf_set_lp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
276 {
277         double f0 = (double)cutoff;
278         double q = (double)resonance;
279         double sr = (double)sample_rate;
280
281         self->g = tan(M_PI * (f0 / sr));
282         self->k = 1.0 / q;
283
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];
287
288         self->m[0] = 0.0;
289         self->m[1] = 0.0;
290         self->m[2] = 1.0;
291 }
292
293 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
294 {
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);
299
300         self->g = tan(M_PI * (f0 / sr));
301         self->k = 1.0 / (q * A);
302
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];
306
307         self->m[0] = 1.0;
308         self->m[1] = self->k * (A * A - 1.0);
309         self->m[2] = 0.0;
310 }
311
312 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
313 {
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);
318
319         self->g = tan(M_PI * (f0 / sr));
320         self->k = 1.0 / q;
321
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];
325
326         self->m[0] = A * A;
327         self->m[1] = self->k * (1.0 - A) * A;
328         self->m[2] = 1.0 - A * A;
329 }
330
331 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
332 {
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);
337
338         self->g = tan(M_PI * (f0 / sr));
339         self->k = 1.0 / q;
340
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];
344
345         self->m[0] = 1.0;
346         self->m[1] = self->k * (A - 1.0);
347         self->m[2] = A * A - 1.0;
348 }
349
350 static float run_linear_svf(struct linear_svf *self, float in)
351 {
352         double v[3];
353         double din = (double)in;
354         double out;
355
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]);
359
360         self->s[0] = (2.0 * v[0]) - self->s[0];
361         self->s[1] = (2.0 * v[1]) - self->s[1];
362
363         out = (self->m[0] * din)
364                 + (self->m[1] * v[0])
365                 + (self->m[2] * v[1]);
366
367         return (float)out;
368 }
369
370 static void
371 run(LV2_Handle instance, uint32_t n_samples)
372 {
373         Aeq* aeq = (Aeq*)instance;
374
375         const float* const input = aeq->input;
376         float* const output = aeq->output;
377
378         float srate = aeq->srate;
379         float in0, out;
380         uint32_t i, j;
381
382         if (*(aeq->shelftogl) > 0.5) {
383                 linear_svf_set_lowshelf(&aeq->v_filter[0], *(aeq->g[0]), srate, *(aeq->f0[0]), 0.7071068);
384         } else {
385                 linear_svf_set_hp(&aeq->v_filter[0], srate, *(aeq->f0[0]), 0.7071068);
386         }
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]));
391
392         if (*(aeq->shelftogh) > 0.5) {
393                 linear_svf_set_highshelf(&aeq->v_filter[5], *(aeq->g[5]), srate, *(aeq->f0[5]), 0.7071068);
394         } else {
395                 linear_svf_set_lp(&aeq->v_filter[5], srate, *(aeq->f0[5]), 0.7071068);
396         }
397
398         for (i = 0; i < n_samples; i++) {
399                 in0 = input[i];
400                 out = in0;
401                 for (j = 0; j < BANDS; j++) {
402                         if (*(aeq->filtog[j]) > 0.5)
403                                 out = run_linear_svf(&aeq->v_filter[j], out);
404                 }
405                 output[i] = out * from_dB(*(aeq->master));
406         }
407
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;
412                 }
413                 if (aeq->v_g[i] != *(aeq->g[i])) {
414                         aeq->v_g[i] = *(aeq->g[i]);
415                         aeq->need_expose = true;
416                 }
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;
420                 }
421                 if (aeq->v_filtog[i] != *(aeq->filtog[i])) {
422                         aeq->v_filtog[i] = *(aeq->filtog[i]);
423                         aeq->need_expose = true;
424                 }
425                 if (aeq->v_shelftogl != *(aeq->shelftogl)) {
426                         aeq->v_shelftogl = *(aeq->shelftogl);
427                         aeq->need_expose = true;
428                 }
429                 if (aeq->v_shelftogh != *(aeq->shelftogh)) {
430                         aeq->v_shelftogh = *(aeq->shelftogh);
431                         aeq->need_expose = true;
432                 }
433                 if (aeq->v_master != *(aeq->master)) {
434                         aeq->v_master = *(aeq->master);
435                         aeq->need_expose = true;
436                 }
437         }
438
439 #ifdef LV2_EXTENDED
440         if (aeq->need_expose && aeq->queue_draw) {
441                 aeq->need_expose = false;
442                 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
443         }
444 #endif
445 }
446
447
448 #ifdef LV2_EXTENDED
449 static float
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);
455         double A;
456         double m0, m1, m2, g, k;
457         int j = 0;
458
459         // low
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) {
468                         // lowshelf
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));
470                 } else {
471                         // hp:
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));
473                 }
474                 j++;
475         }
476
477         // peq1:
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)));
486                 j++;
487         }
488
489         // peq2:
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)));
498                 j++;
499         }
500
501         // peq3:
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)));
510                 j++;
511         }
512
513         // peq4:
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)));
522                 j++;
523         }
524
525         // high
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) {
534                         // highshelf:
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));
536                 } else {
537                         // lp:
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));
539                 }
540                 j++;
541         }
542
543         return cabs(H);
544 }
545
546 static LV2_Inline_Display_Image_Surface *
547 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
548 {
549         Aeq* self = (Aeq*)instance;
550         uint32_t h = MIN (w, max_h);
551
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);
555                 self->w = w;
556                 self->h = h;
557         }
558
559         cairo_t* cr = cairo_create (self->display);
560
561         // clear background
562         cairo_rectangle (cr, 0, 0, w, h);
563         cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
564         cairo_fill (cr);
565
566         cairo_set_line_width(cr, 1.0);
567
568         // draw grid 5dB steps
569         const double dash2[] = {1, 3};
570         cairo_save (cr);
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);
574
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);
579                 cairo_stroke (cr);
580         }
581         cairo_restore (cr);
582
583
584         // draw curve
585         cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
586         cairo_move_to (cr, 0, h);
587
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);
595         }
596         cairo_stroke_preserve (cr);
597
598         cairo_line_to (cr, w, h);
599         cairo_close_path (cr);
600         cairo_clip (cr);
601
602         // create RGBA surface
603         cairo_destroy (cr);
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);
609
610         return &self->surf;
611 }
612 #endif
613
614 static const void*
615 extension_data(const char* uri)
616 {
617 #ifdef LV2_EXTENDED
618         static const LV2_Inline_Display_Interface display  = { render_inline };
619         if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
620                 return &display;
621         }
622 #endif
623         return NULL;
624 }
625
626 static void
627 cleanup(LV2_Handle instance)
628 {
629 #ifdef LV2_EXTENDED
630         Aeq* aeq = (Aeq*)instance;
631         if (aeq->display) {
632                 cairo_surface_destroy (aeq->display);
633         }
634 #endif
635         free(instance);
636 }
637
638 static const LV2_Descriptor descriptor = {
639         AEQ_URI,
640         instantiate,
641         connect_port,
642         activate,
643         run,
644         NULL,
645         cleanup,
646         extension_data
647 };
648
649 LV2_SYMBOL_EXPORT
650 const LV2_Descriptor*
651 lv2_descriptor(uint32_t index)
652 {
653         switch (index) {
654         case 0:
655                 return &descriptor;
656         default:
657                 return NULL;
658         }
659 }