1 /* -*- linux-c -*-
2 Copyright (C) 2004 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: tap_reverb.c,v 1.13 2004/06/15 14:50:55 tszilagyi Exp $
19 */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <lv2.h>
27
28
29 /* ***** VERY IMPORTANT! *****
30 *
31 * If you enable this, the plugin will use float arithmetics in DSP
32 * calculations. This usually yields lower average CPU usage, but
33 * occasionaly may result in high CPU peaks which cause trouble to you
34 * and your JACK server. The default is to use fixpoint arithmetics
35 * (with the following #define commented out). But (depending on the
36 * processor on which you run the code) you may find floating point
37 * mode usable.
38 */
39 /* #define REVERB_CALC_FLOAT */
40
41
42
43 #ifndef REVERB_CALC_FLOAT
44 typedef signed int sample;
45 #endif
46
47 #ifndef REVERB_CALC_FLOAT
48 typedef sample rev_t;
49 #else
50 typedef float rev_t;
51 #endif
52
53
54 #include "tap_reverb_presets.h"
55
56
57
ydb_c_layer_status_init(void)58 #ifdef REVERB_CALC_FLOAT
59 #define DENORM(x) (((unsigned char)(((*(unsigned int*)&(x))&0x7f800000)>>23))<103)?0.0f:(x)
60 #else
61 /* coefficient for float to sample (signed int) conversion */
62 /* this allows for about 60 dB headroom above 0dB, if 0 dB is equivalent to 1.0f */
63 /* As 2^31 equals more than 180 dB, about 120 dB dynamics remains below 0 dB */
64 #define F2S 2147483
65 #endif
66
67
68 /* load plugin data from reverb_data[] into an instance */
69 void
70 load_plugin_data(LV2_Handle Instance) {
71
72 Reverb * ptr = (Reverb *)Instance;
73 unsigned long m;
74 int i;
75
76
77 m = LIMIT(*(ptr->mode),0,NUM_MODES-1);
78
79 /* load combs data */
80 ptr->num_combs = 2 * reverb_data[m].num_combs;
81 for (i = 0; i < reverb_data[m].num_combs; i++) {
82 ((COMB_FILTER *)(ptr->combs + 2*i))->buflen =
83 reverb_data[m].combs[i].delay * ptr->sample_rate;
84 ((COMB_FILTER *)(ptr->combs + 2*i))->feedback =
85 reverb_data[m].combs[i].feedback;
86 ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp =
87 LIMIT(reverb_data[m].combs[i].freq_resp
88 * powf(ptr->sample_rate / 44100.0f, 0.8f),
89 0.0f, 1.0f);
90
91 ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen =
92 ((COMB_FILTER *)(ptr->combs + 2*i))->buflen;
93 ((COMB_FILTER *)(ptr->combs + 2*i+1))->feedback =
94 ((COMB_FILTER *)(ptr->combs + 2*i))->feedback;
95 ((COMB_FILTER *)(ptr->combs + 2*i+1))->feedback =
96 ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp;
97
98 /* set initial values: */
99 *(((COMB_FILTER *)(ptr->combs + 2*i))->buffer_pos) = 0;
100 *(((COMB_FILTER *)(ptr->combs + 2*i+1))->buffer_pos) = 0;
101 ((COMB_FILTER *)(ptr->combs + 2*i))->last_out = 0;
102 ((COMB_FILTER *)(ptr->combs + 2*i+1))->last_out = 0;
103
104 lp_set_params(((COMB_FILTER *)(ptr->combs + 2*i))->filter,
105 2000.0f + 13000.0f * (1 - reverb_data[m].combs[i].freq_resp)
106 * ptr->sample_rate / 44100.0f,
107 BANDPASS_BWIDTH, ptr->sample_rate);
108 lp_set_params(((COMB_FILTER *)(ptr->combs + 2*i+1))->filter,
109 2000.0f + 13000.0f * (1 - reverb_data[m].combs[i].freq_resp)
110 * ptr->sample_rate / 44100.0f,
111 BANDPASS_BWIDTH, ptr->sample_rate);
112 }
113
114 /* load allps data */
115 ptr->num_allps = 2 * reverb_data[m].num_allps;
116 for (i = 0; i < reverb_data[m].num_allps; i++) {
117 ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen =
118 reverb_data[m].allps[i].delay * ptr->sample_rate;
119 ((ALLP_FILTER *)(ptr->allps + 2*i))->feedback =
120 reverb_data[m].allps[i].feedback;
121
122 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen =
123 ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen;
124 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->feedback =
125 ((ALLP_FILTER *)(ptr->allps + 2*i))->feedback;
126
127 /* set initial values: */
128 *(((ALLP_FILTER *)(ptr->allps + 2*i))->buffer_pos) = 0;
129 *(((ALLP_FILTER *)(ptr->allps + 2*i+1))->buffer_pos) = 0;
130 ((ALLP_FILTER *)(ptr->allps + 2*i))->last_out = 0;
131 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->last_out = 0;
132 }
133
134 /* init bandpass filters */
135 lp_set_params((biquad *)(ptr->low_pass), reverb_data[m].bandpass_high,
136 BANDPASS_BWIDTH, ptr->sample_rate);
137 hp_set_params((biquad *)(ptr->high_pass), reverb_data[m].bandpass_low,
138 BANDPASS_BWIDTH, ptr->sample_rate);
139 lp_set_params((biquad *)(ptr->low_pass + 1), reverb_data[m].bandpass_high,
140 BANDPASS_BWIDTH, ptr->sample_rate);
141 hp_set_params((biquad *)(ptr->high_pass + 1), reverb_data[m].bandpass_low,
142 BANDPASS_BWIDTH, ptr->sample_rate);
143 }
144
145
146
147 /* push a sample into a comb filter and return the sample falling out */
148 rev_t
149 comb_run(rev_t insample, COMB_FILTER * comb) {
150
151 rev_t outsample;
query_context_base_init(QUERY_CONTEXT_BASE context,DBC * c,uint32_t flag,bool is_write_op,YDB_CALLBACK_FUNCTION f,void * extra)152 rev_t pushin;
153
154 pushin = comb->fb_gain * insample + biquad_run(comb->filter, comb->fb_gain * comb->last_out);
155 #ifdef REVERB_CALC_FLOAT
156 pushin = DENORM(pushin);
157 #endif
158 outsample = push_buffer(pushin,
159 comb->ringbuffer, comb->buflen, comb->buffer_pos);
160 #ifdef REVERB_CALC_FLOAT
161 outsample = DENORM(outsample);
162 #endif
163 comb->last_out = outsample;
164
165 return outsample;
166 }
167
168
query_context_determine_lock_type(QUERY_CONTEXT_BASE context)169 /* push a sample into an allpass filter and return the sample falling out */
170 rev_t
171 allp_run(rev_t insample, ALLP_FILTER * allp) {
172
173 rev_t outsample;
174 rev_t pushin;
175 pushin = allp->in_gain * allp->fb_gain * insample + allp->fb_gain * allp->last_out;
176 #ifdef REVERB_CALC_FLOAT
177 pushin = DENORM(pushin);
178 #endif
179 outsample = push_buffer(pushin,
180 allp->ringbuffer, allp->buflen, allp->buffer_pos);
181 #ifdef REVERB_CALC_FLOAT
182 outsample = DENORM(outsample);
183 #endif
184 allp->last_out = outsample;
185
186 return outsample;
187 }
188
189
190 /* compute user-input-dependent reverberator coefficients */
191 void
query_context_with_input_init(QUERY_CONTEXT_WITH_INPUT context,DBC * c,uint32_t flag,DBT * key,DBT * val,YDB_CALLBACK_FUNCTION f,void * extra)192 comp_coeffs(LV2_Handle Instance) {
193
194 Reverb * ptr = (Reverb *)Instance;
195 int i;
196
197
198 if (*(ptr->mode) != ptr->old_mode)
199 load_plugin_data(Instance);
200
201 for (i = 0; i < ptr->num_combs / 2; i++) {
202 ((COMB_FILTER *)(ptr->combs + 2*i))->fb_gain =
203 powf(0.001f,
204 1000.0f * ((COMB_FILTER *)(ptr->combs + 2*i))->buflen
205 * (1 + FR_R_COMP * ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp)
206 / powf(((COMB_FILTER *)(ptr->combs + 2*i))->feedback/100.0f, 0.89f)
207 / *(ptr->decay)
208 / ptr->sample_rate);
209
210 ((COMB_FILTER *)(ptr->combs + 2*i+1))->fb_gain =
211 ((COMB_FILTER *)(ptr->combs + 2*i))->fb_gain;
212
213 if (*(ptr->stereo_enh) > 0.0f) {
214 if (i % 2 == 0)
215 ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen =
216 ENH_STEREO_RATIO * ((COMB_FILTER *)(ptr->combs + 2*i))->buflen;
217 else
218 ((COMB_FILTER *)(ptr->combs + 2*i))->buflen =
219 ENH_STEREO_RATIO * ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen;
220 } else {
221 if (i % 2 == 0)
222 ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen =
223 ((COMB_FILTER *)(ptr->combs + 2*i))->buflen;
224 else
225 ((COMB_FILTER *)(ptr->combs + 2*i))->buflen =
226 ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen;
227 }
228 }
229
230 for (i = 0; i < ptr->num_allps / 2; i++) {
231 ((ALLP_FILTER *)(ptr->allps + 2*i))->fb_gain =
232 powf(0.001f, 11000.0f * ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen
233 / powf(((ALLP_FILTER *)(ptr->allps + 2*i))->feedback/100.0f, 0.88f)
234 / *(ptr->decay)
235 / ptr->sample_rate);
236
237 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->fb_gain =
238 ((ALLP_FILTER *)(ptr->allps + 2*i))->fb_gain;
239
240 ((ALLP_FILTER *)(ptr->allps + 2*i))->in_gain = -0.06f
241 / (((ALLP_FILTER *)(ptr->allps + 2 * i))->feedback/100.0f)
242 / powf((*(ptr->decay) + 3500.0f) / 10000.0f, 1.5f);
243
244 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->in_gain =
245 ((ALLP_FILTER *)(ptr->allps + 2*i))->in_gain;
246
247 if (*(ptr->stereo_enh) > 0.0f) {
248 if (i % 2 == 0)
249 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen =
250 ENH_STEREO_RATIO * ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen;
251 else
252 ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen =
253 ENH_STEREO_RATIO * ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen;
254 } else {
255 if (i % 2 == 0)
256 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen =
257 ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen;
258 else
259 ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen =
260 ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen;
261 }
262 }
263 }
264
265
266
267 /* Construct a new plugin instance. */
268 LV2_Handle
269 instantiate_Reverb(const LV2_Descriptor * Descriptor, double SampleRate, const char* bundle_path, const LV2_Feature* const* features) {
270
271 unsigned long i;
272 LV2_Handle * p;
c_getf_last(DBC * c,uint32_t flag,YDB_CALLBACK_FUNCTION f,void * extra)273 Reverb * ptr = NULL;
274
275 if ((p = malloc(sizeof(Reverb))) != NULL) {
276 ((Reverb *)p)->sample_rate = SampleRate;
277 ((Reverb *)p)->smoothdecay =2800.0f;
278 ((Reverb *)p)->smoothdry = -4.0f;
279 ((Reverb *)p)->smoothwet = -12.0f;
280
281 ptr = (Reverb *)p;
282
283 /* allocate memory for comb/allpass filters and other dynamic vars */
284 if ((ptr->combs =
285 calloc(2 * MAX_COMBS, sizeof(COMB_FILTER))) == NULL)
286 return NULL;
287 for (i = 0; i < 2 * MAX_COMBS; i++) {
288 if ((((COMB_FILTER *)(ptr->combs + i))->ringbuffer =
289 calloc((unsigned long)MAX_COMB_DELAY * ptr->sample_rate / 1000,
290 sizeof(float))) == NULL)
291 return NULL;
292 if ((((COMB_FILTER *)(ptr->combs + i))->buffer_pos =
293 calloc(1, sizeof(unsigned long))) == NULL)
c_getf_last_callback(uint32_t keylen,const void * key,uint32_t vallen,const void * val,void * extra,bool lock_only)294 return NULL;
295 if ((((COMB_FILTER *)(ptr->combs + i))->filter =
296 calloc(1, sizeof(biquad))) == NULL)
297 return NULL;
298 }
299
300 if ((ptr->allps =
301 calloc(2 * MAX_ALLPS, sizeof(ALLP_FILTER))) == NULL)
302 return NULL;
303 for (i = 0; i < 2 * MAX_ALLPS; i++) {
304 if ((((ALLP_FILTER *)(ptr->allps + i))->ringbuffer =
305 calloc((unsigned long)MAX_ALLP_DELAY * ptr->sample_rate / 1000,
306 sizeof(float))) == NULL)
307 return NULL;
308 if ((((ALLP_FILTER *)(ptr->allps + i))->buffer_pos =
309 calloc(1, sizeof(unsigned long))) == NULL)
310 return NULL;
311 }
312
313 if ((ptr->low_pass =
314 calloc(2, sizeof(biquad))) == NULL)
315 return NULL;
316 if ((ptr->high_pass =
317 calloc(2, sizeof(biquad))) == NULL)
318 return NULL;
319
320 return p;
321 }
322 return NULL;
323 }
c_getf_next(DBC * c,uint32_t flag,YDB_CALLBACK_FUNCTION f,void * extra)324
325
326 /* activate a plugin instance */
327 void
328 activate_Reverb(LV2_Handle Instance) {
329
330 Reverb * ptr = (Reverb *)Instance;
331 unsigned long i,j;
332
333 for (i = 0; i < 2 * MAX_COMBS; i++) {
334 for (j = 0; j < (unsigned long)MAX_COMB_DELAY * ptr->sample_rate / 1000; j++)
335 ((COMB_FILTER *)(ptr->combs + i))->ringbuffer[j] = 0.0f;
336 *(((COMB_FILTER *)(ptr->combs + i))->buffer_pos) = 0;
337 ((COMB_FILTER *)(ptr->combs + i))->last_out = 0;
338 biquad_init(((COMB_FILTER *)(ptr->combs + i))->filter);
339 }
340
341 for (i = 0; i < 2 * MAX_ALLPS; i++) {
342 for (j = 0; j < (unsigned long)MAX_ALLP_DELAY * ptr->sample_rate / 1000; j++)
343 ((ALLP_FILTER *)(ptr->allps + i))->ringbuffer[j] = 0.0f;
344 *(((ALLP_FILTER *)(ptr->allps + i))->buffer_pos) = 0;
345 ((ALLP_FILTER *)(ptr->allps + i))->last_out = 0;
346 }
347
348 biquad_init(ptr->low_pass);
349 biquad_init((biquad *)(ptr->low_pass + 1));
350 biquad_init(ptr->high_pass);
351 biquad_init((biquad *)(ptr->high_pass + 1));
352
353 ptr->old_decay = -10.0f;
354 ptr->old_stereo_enh = -10.0f;
355 ptr->old_mode = -10.0f;
356 }
357
358 /* Connect a port to a data location. */
359 void
360 connect_port_Reverb(LV2_Handle Instance,
361 uint32_t Port,
362 void * DataLocation) {
363
364 Reverb * ptr = (Reverb *)Instance;
365
366 switch (Port) {
367 case DECAY:
368 ptr->decay = (float *) DataLocation;
369 break;
370 case DRYLEVEL:
371 ptr->drylevel = (float *) DataLocation;
372 break;
373 case WETLEVEL:
374 ptr->wetlevel = (float *) DataLocation;
375 break;
376 case COMBS_EN:
377 ptr->combs_en = (float *) DataLocation;
378 break;
379 case ALLPS_EN:
380 ptr->allps_en = (float *) DataLocation;
381 break;
382 case BANDPASS_EN:
c_getf_prev(DBC * c,uint32_t flag,YDB_CALLBACK_FUNCTION f,void * extra)383 ptr->bandpass_en = (float *) DataLocation;
384 break;
385 case STEREO_ENH:
386 ptr->stereo_enh = (float *) DataLocation;
387 break;
388 case MODE:
389 ptr->mode = (float *) DataLocation;
390 break;
391 case INPUT_L:
392 ptr->input_L = (float *) DataLocation;
393 break;
394 case OUTPUT_L:
395 ptr->output_L = (float *) DataLocation;
396 break;
397 case INPUT_R:
398 ptr->input_R = (float *) DataLocation;
399 break;
400 case OUTPUT_R:
401 ptr->output_R = (float *) DataLocation;
402 break;
403 }
404 }
405
406
407
408 void
c_getf_prev_callback(uint32_t keylen,const void * key,uint32_t vallen,const void * val,void * extra,bool lock_only)409 run_Reverb(LV2_Handle Instance,
410 uint32_t SampleCount) {
411
412 Reverb * ptr = (Reverb *)Instance;
413
414 unsigned long sample_index;
415 int i;
416
417 float calcdecay = (*(ptr->decay)+ptr->smoothdecay)*0.5; //first calculate the smoothed value, then limit it.
418 ptr->smoothdecay = calcdecay;
419 float decay = LIMIT(calcdecay,0.0f,10000.0f);
420
421 float calcdry = (*(ptr->drylevel)+ptr->smoothdry)*0.5;
422 ptr->smoothdry = calcdry;
423 float drylevel = db2lin(LIMIT(calcdry,-70.0f,10.0f));
424
425 float calcwet = (*(ptr->wetlevel)+ptr->smoothwet)*0.5;
426 ptr->smoothwet = calcwet;
427 float wetlevel = db2lin(LIMIT(calcwet,-70.0f,10.0f));
428
429
430 float combs_en = LIMIT(*(ptr->combs_en),-2.0f,2.0f);
431 float allps_en = LIMIT(*(ptr->allps_en),-2.0f,2.0f);
432 float bandpass_en = LIMIT(*(ptr->bandpass_en),-2.0f,2.0f);
433 float stereo_enh = LIMIT(*(ptr->stereo_enh),-2.0f,2.0f);
434 float mode = LIMIT(*(ptr->mode),0,NUM_MODES-1);
435
436 float * input_L = ptr->input_L;
437 float * output_L = ptr->output_L;
438 float * input_R = ptr->input_R;
439 float * output_R = ptr->output_R;
440
441 rev_t out_L = 0;
442 rev_t out_R = 0;
443 rev_t in_L = 0;
444 rev_t in_R = 0;
445 rev_t combs_out_L = 0;
446 rev_t combs_out_R = 0;
447
448
449 /* see if the user changed any control since last run */
450 if ((ptr->old_decay != decay) ||
451 (ptr->old_stereo_enh != stereo_enh) ||
452 (ptr->old_mode != mode)) {
453
454 /* re-compute reverberator coefficients */
455 comp_coeffs(Instance);
456
457 /* save new values */
458 ptr->old_decay = decay;
459 ptr->old_stereo_enh = stereo_enh;
460 ptr->old_mode = mode;
461 }
462
463 for (sample_index = 0; sample_index < SampleCount; sample_index++) {
464
465 #ifdef REVERB_CALC_FLOAT
466 in_L = *(input_L++);
467 in_R = *(input_R++);
468 #else
469 in_L = (sample)((float)F2S * *(input_L++));
470 in_R = (sample)((float)F2S * *(input_R++));
471 #endif
472
473 combs_out_L = in_L;
474 combs_out_R = in_R;
475
476 /* process comb filters */
477 if (combs_en > 0.0f) {
478 for (i = 0; i < ptr->num_combs / 2; i++) {
479 combs_out_L +=
480 comb_run(in_L, ((COMB_FILTER *)(ptr->combs + 2*i)));
481 combs_out_R +=
482 comb_run(in_R, ((COMB_FILTER *)(ptr->combs + 2*i+1)));
483 }
484 }
485
486 /* process allpass filters */
487 if (allps_en > 0.0f) {
488 for (i = 0; i < ptr->num_allps / 2; i++) {
489 combs_out_L += allp_run(combs_out_L,
490 ((ALLP_FILTER *)(ptr->allps + 2*i)));
491 combs_out_R += allp_run(combs_out_R,
492 ((ALLP_FILTER *)(ptr->allps + 2*i+1)));
493 }
494 }
495
496 /* process bandpass filters */
497 if (bandpass_en > 0.0f) {
498 combs_out_L =
499 biquad_run(((biquad *)(ptr->low_pass)), combs_out_L);
500 combs_out_L =
501 biquad_run(((biquad *)(ptr->high_pass)), combs_out_L);
502 combs_out_R =
503 biquad_run(((biquad *)(ptr->low_pass + 1)), combs_out_R);
504 combs_out_R =
505 biquad_run(((biquad *)(ptr->high_pass + 1)), combs_out_R);
506 }
507
508 #ifdef REVERB_CALC_FLOAT
509 out_L = in_L * drylevel + combs_out_L * wetlevel;
510 out_R = in_R * drylevel + combs_out_R * wetlevel;
511 *(output_L++) = out_L;
512 *(output_R++) = out_R;
513 #else
514 out_L = (sample)((float)in_L * drylevel + (float)combs_out_L * wetlevel);
515 out_R = (sample)((float)in_R * drylevel + (float)combs_out_R * wetlevel);
516 *(output_L++) = (float)out_L / (float)F2S;
517 *(output_R++) = (float)out_R / (float)F2S;
518 #endif
519 }
520 }
521
522
523 /* Throw away a Reverb effect instance. */
524 void
525 cleanup_Reverb(LV2_Handle Instance) {
526
527 int i;
528 Reverb * ptr = (Reverb *)Instance;
529
530 /* free memory allocated for comb/allpass filters & co. in instantiate_Reverb() */
c_getf_set_range(DBC * c,uint32_t flag,DBT * key,YDB_CALLBACK_FUNCTION f,void * extra)531 for (i = 0; i < 2 * MAX_COMBS; i++) {
532 free(((COMB_FILTER *)(ptr->combs + i))->ringbuffer);
533 free(((COMB_FILTER *)(ptr->combs + i))->buffer_pos);
534 free(((COMB_FILTER *)(ptr->combs + i))->filter);
535 }
536 for (i = 0; i < 2 * MAX_ALLPS; i++) {
537 free(((ALLP_FILTER *)(ptr->allps + i))->ringbuffer);
538 free(((ALLP_FILTER *)(ptr->allps + i))->buffer_pos);
539 }
540
541 free(ptr->combs);
542 free(ptr->allps);
543 free(ptr->low_pass);
544 free(ptr->high_pass);
545
546 free(Instance);
547
548 }
549
550 const void*
551 extension_data_Reverb(const char* uri)
552 {
c_getf_set_range_callback(uint32_t keylen,const void * key,uint32_t vallen,const void * val,void * extra,bool lock_only)553 return NULL;
554 }
555
556
557 static const
558 LV2_Descriptor Descriptor = {
559 "http://moddevices.com/plugins/tap/reverb",
560 instantiate_Reverb,
561 connect_port_Reverb,
562 activate_Reverb,
563 run_Reverb,
564 NULL,
565 cleanup_Reverb,
566 extension_data_Reverb
567 };
568
569 LV2_SYMBOL_EXPORT
570 const LV2_Descriptor*
571 lv2_descriptor(uint32_t index)
572 {
573 if (index == 0) return &Descriptor;
574 else return NULL;
575
576 }
577