816ea4667271281849a3f33df8235ec83213cb20
[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
114         bool need_expose;
115
116 #ifdef LV2_EXTENDED
117         LV2_Inline_Display_Image_Surface surf;
118         cairo_surface_t*                 display;
119         LV2_Inline_Display*              queue_draw;
120         uint32_t                         w, h;
121 #endif
122 } Aeq;
123
124 static LV2_Handle
125 instantiate(const LV2_Descriptor* descriptor,
126             double rate,
127             const char* bundle_path,
128             const LV2_Feature* const* features)
129 {
130         int i;
131         Aeq* aeq = (Aeq*)malloc(sizeof(Aeq));
132         aeq->srate = rate;
133         
134 #ifdef LV2_EXTENDED
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;
138                 }
139         }
140 #endif
141
142         for (i = 0; i < BANDS; i++)
143                 linear_svf_reset(&aeq->v_filter[i]);
144
145         aeq->need_expose = true;
146         aeq->display = NULL;
147
148         return (LV2_Handle)aeq;
149 }
150
151 static void
152 connect_port(LV2_Handle instance,
153              uint32_t port,
154              void* data)
155 {
156         Aeq* aeq = (Aeq*)instance;
157
158         switch ((PortIndex)port) {
159         case AEQ_SHELFTOGL:
160                 aeq->shelftogl = (float*)data;
161                 break;
162         case AEQ_FREQL:
163                 aeq->f0[0] = (float*)data;
164                 break;
165         case AEQ_GAINL:
166                 aeq->g[0] = (float*)data;
167                 break;
168         case AEQ_FREQ1:
169                 aeq->f0[1] = (float*)data;
170                 break;
171         case AEQ_GAIN1:
172                 aeq->g[1] = (float*)data;
173                 break;
174         case AEQ_BW1:
175                 aeq->bw[1] = (float*)data;
176                 break;
177         case AEQ_FREQ2:
178                 aeq->f0[2] = (float*)data;
179                 break;
180         case AEQ_GAIN2:
181                 aeq->g[2] = (float*)data;
182                 break;
183         case AEQ_BW2:
184                 aeq->bw[2] = (float*)data;
185                 break;
186         case AEQ_FREQ3:
187                 aeq->f0[3] = (float*)data;
188                 break;
189         case AEQ_GAIN3:
190                 aeq->g[3] = (float*)data;
191                 break;
192         case AEQ_BW3:
193                 aeq->bw[3] = (float*)data;
194                 break;
195         case AEQ_FREQ4:
196                 aeq->f0[4] = (float*)data;
197                 break;
198         case AEQ_GAIN4:
199                 aeq->g[4] = (float*)data;
200                 break;
201         case AEQ_BW4:
202                 aeq->bw[4] = (float*)data;
203                 break;
204         case AEQ_SHELFTOGH:
205                 aeq->shelftogh = (float*)data;
206                 break;
207         case AEQ_FREQH:
208                 aeq->f0[5] = (float*)data;
209                 break;
210         case AEQ_GAINH:
211                 aeq->g[5] = (float*)data;
212                 break;
213         case AEQ_MASTER:
214                 aeq->master = (float*)data;
215                 break;
216         case AEQ_FILTOGL:
217                 aeq->filtog[0] = (float*)data;
218                 break;
219         case AEQ_FILTOG1:
220                 aeq->filtog[1] = (float*)data;
221                 break;
222         case AEQ_FILTOG2:
223                 aeq->filtog[2] = (float*)data;
224                 break;
225         case AEQ_FILTOG3:
226                 aeq->filtog[3] = (float*)data;
227                 break;
228         case AEQ_FILTOG4:
229                 aeq->filtog[4] = (float*)data;
230                 break;
231         case AEQ_FILTOGH:
232                 aeq->filtog[5] = (float*)data;
233                 break;
234         case AEQ_INPUT:
235                 aeq->input = (float*)data;
236                 break;
237         case AEQ_OUTPUT:
238                 aeq->output = (float*)data;
239                 break;
240         }
241 }
242
243 static void
244 activate(LV2_Handle instance)
245 {
246         int i;
247         Aeq* aeq = (Aeq*)instance;
248
249         for (i = 0; i < BANDS; i++)
250                 linear_svf_reset(&aeq->v_filter[i]);
251 }
252
253 // SVF filters
254 // http://www.cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
255
256 static void linear_svf_set_hp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
257 {
258         double f0 = (double)cutoff;
259         double q = (double)resonance;
260         double sr = (double)sample_rate;
261
262         self->g = tan(M_PI * (f0 / sr));
263         self->k = 1.0 / q;
264
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];
268
269         self->m[0] = 1.0;
270         self->m[1] = -self->k;
271         self->m[2] = -1.0;
272 }
273
274 static void linear_svf_set_lp(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
275 {
276         double f0 = (double)cutoff;
277         double q = (double)resonance;
278         double sr = (double)sample_rate;
279
280         self->g = tan(M_PI * (f0 / sr));
281         self->k = 1.0 / q;
282
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];
286
287         self->m[0] = 0.0;
288         self->m[1] = 0.0;
289         self->m[2] = 1.0;
290 }
291
292 static void linear_svf_set_peq(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float bandwidth)
293 {
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);
298
299         self->g = tan(M_PI * (f0 / sr));
300         self->k = 1.0 / (q * A);
301
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];
305
306         self->m[0] = 1.0;
307         self->m[1] = self->k * (A * A - 1.0);
308         self->m[2] = 0.0;
309 }
310
311 static void linear_svf_set_highshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
312 {
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);
317
318         self->g = tan(M_PI * (f0 / sr));
319         self->k = 1.0 / q;
320
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];
324
325         self->m[0] = A * A;
326         self->m[1] = self->k * (1.0 - A) * A;
327         self->m[2] = 1.0 - A * A;
328 }
329
330 static void linear_svf_set_lowshelf(struct linear_svf *self, float gdb, float sample_rate, float cutoff, float resonance)
331 {
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);
336
337         self->g = tan(M_PI * (f0 / sr));
338         self->k = 1.0 / q;
339
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];
343
344         self->m[0] = 1.0;
345         self->m[1] = self->k * (A - 1.0);
346         self->m[2] = A * A - 1.0;
347 }
348
349 static float run_linear_svf(struct linear_svf *self, float in)
350 {
351         double v[3];
352         double din = (double)in;
353         double out;
354
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]);
358
359         self->s[0] = (2.0 * v[0]) - self->s[0];
360         self->s[1] = (2.0 * v[1]) - self->s[1];
361
362         out = (self->m[0] * din)
363                 + (self->m[1] * v[0])
364                 + (self->m[2] * v[1]);
365
366         return (float)out;
367 }
368
369 static void
370 run(LV2_Handle instance, uint32_t n_samples)
371 {
372         Aeq* aeq = (Aeq*)instance;
373
374         const float* const input = aeq->input;
375         float* const output = aeq->output;
376
377         float srate = aeq->srate;
378         float in0, out;
379         uint32_t i, j;
380
381         if (*(aeq->shelftogl) > 0.5) {
382                 linear_svf_set_lowshelf(&aeq->v_filter[0], *(aeq->g[0]), srate, *(aeq->f0[0]), 0.7071068);
383         } else {
384                 linear_svf_set_hp(&aeq->v_filter[0], srate, *(aeq->f0[0]), 0.7071068);
385         }
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]));
390
391         if (*(aeq->shelftogh) > 0.5) {
392                 linear_svf_set_highshelf(&aeq->v_filter[5], *(aeq->g[5]), srate, *(aeq->f0[5]), 0.7071068);
393         } else {
394                 linear_svf_set_lp(&aeq->v_filter[5], srate, *(aeq->f0[5]), 0.7071068);
395         }
396
397         for (i = 0; i < n_samples; i++) {
398                 in0 = input[i];
399                 out = in0;
400                 for (j = 0; j < BANDS; j++) {
401                         if (*(aeq->filtog[j]) > 0.5)
402                                 out = run_linear_svf(&aeq->v_filter[j], out);
403                 }
404                 output[i] = out * from_dB(*(aeq->master));
405         }
406
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;
411                 }
412                 if (aeq->v_g[i] != *(aeq->g[i])) {
413                         aeq->v_g[i] = *(aeq->g[i]);
414                         aeq->need_expose = true;
415                 }
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;
419                 }
420                 if (aeq->v_filtog[i] != *(aeq->filtog[i])) {
421                         aeq->v_filtog[i] = *(aeq->filtog[i]);
422                         aeq->need_expose = true;
423                 }
424                 if (aeq->v_shelftogl != *(aeq->shelftogl)) {
425                         aeq->v_shelftogl = *(aeq->shelftogl);
426                         aeq->need_expose = true;
427                 }
428                 if (aeq->v_shelftogh != *(aeq->shelftogh)) {
429                         aeq->v_shelftogh = *(aeq->shelftogh);
430                         aeq->need_expose = true;
431                 }
432         }
433
434 #ifdef LV2_EXTENDED
435         if (aeq->need_expose && aeq->queue_draw) {
436                 aeq->need_expose = false;
437                 aeq->queue_draw->queue_draw (aeq->queue_draw->handle);
438         }
439 #endif
440 }
441
442
443 #ifdef LV2_EXTENDED
444 static float
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);
450         double A;
451         double m0, m1, m2, g, k;
452         int j = 0;
453
454         // low
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) {
463                         // lowshelf
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));
465                 } else {
466                         // hp:
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));
468                 }
469                 j++;
470         }
471
472         // peq1:
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)));
481                 j++;
482         }
483
484         // peq2:
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)));
493                 j++;
494         }
495
496         // peq3:
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)));
505                 j++;
506         }
507
508         // peq4:
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)));
517                 j++;
518         }
519
520         // high
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) {
529                         // highshelf:
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));
531                 } else {
532                         // lp:
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));
534                 }
535                 j++;
536         }
537
538         return cabs(H);
539 }
540
541 static LV2_Inline_Display_Image_Surface *
542 render_inline (LV2_Handle instance, uint32_t w, uint32_t max_h)
543 {
544         Aeq* self = (Aeq*)instance;
545         uint32_t h = MIN (w, max_h);
546
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);
550                 self->w = w;
551                 self->h = h;
552         }
553
554         cairo_t* cr = cairo_create (self->display);
555
556         // clear background
557         cairo_rectangle (cr, 0, 0, w, h);
558         cairo_set_source_rgba (cr, .2, .2, .2, 1.0);
559         cairo_fill (cr);
560
561         cairo_set_line_width(cr, 1.0);
562
563         // draw grid 10dB steps
564         const double dash2[] = {1, 3};
565         cairo_save (cr);
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);
569
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);
574                 cairo_stroke (cr);
575         }
576         cairo_restore (cr);
577
578
579         // draw curve
580         cairo_set_source_rgba (cr, .8, .8, .8, 1.0);
581         cairo_move_to (cr, 0, h);
582
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);
590         }
591         cairo_stroke_preserve (cr);
592
593         cairo_line_to (cr, w, h);
594         cairo_close_path (cr);
595         cairo_clip (cr);
596
597         // create RGBA surface
598         cairo_destroy (cr);
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);
604
605         return &self->surf;
606 }
607 #endif
608
609 static const void*
610 extension_data(const char* uri)
611 {
612 #ifdef LV2_EXTENDED
613         static const LV2_Inline_Display_Interface display  = { render_inline };
614         if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
615                 return &display;
616         }
617 #endif
618         return NULL;
619 }
620
621 static void
622 cleanup(LV2_Handle instance)
623 {
624 #ifdef LV2_EXTENDED
625         Aeq* aeq = (Aeq*)instance;
626         if (aeq->display) {
627                 cairo_surface_destroy (aeq->display);
628         }
629 #endif
630         free(instance);
631 }
632
633 static const LV2_Descriptor descriptor = {
634         AEQ_URI,
635         instantiate,
636         connect_port,
637         activate,
638         run,
639         NULL,
640         cleanup,
641         extension_data
642 };
643
644 LV2_SYMBOL_EXPORT
645 const LV2_Descriptor*
646 lv2_descriptor(uint32_t index)
647 {
648         switch (index) {
649         case 0:
650                 return &descriptor;
651         default:
652                 return NULL;
653         }
654 }