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_pitch.c,v 1.2 2004/02/21 17:33:36 tszilagyi Exp $
19 */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26
27 #include "ladspa.h"
28 #include "tap_utils.h"
29
30
31 /* The Unique ID of the plugin: */
32
33 #define ID_MONO 2150
34
35 /* The port numbers for the plugin: */
36
37 #define SEMITONE 0
38 #define RATE 1
39 #define DRYLEVEL 2
40 #define WETLEVEL 3
41 #define LATENCY 4
42 #define INPUT 5
43 #define OUTPUT 6
44
45 /* Total number of ports */
46
47
48 #define PORTCOUNT_MONO 7
49
50
51 /* depth of phase mod (yes, this is a magic number) */
52 #define PM_DEPTH 3681.0f
53
54
55 /* another magic number, derived from the above one */
56 #define PM_BUFLEN 16027
57
58
59 /* frequency of the modulation signal (Hz) */
60 #define PM_FREQ 6.0f
61
62
63 #define COS_TABLE_SIZE 1024
64 LADSPA_Data cos_table[COS_TABLE_SIZE];
65
66
67 /* \sqrt{12}{2} used for key frequency computing */
68 #define ROOT_12_2 1.059463094f
69
70
71 /* The structure used to hold port connection information and state */
72
73 typedef struct {
74 LADSPA_Data * rate;
75 LADSPA_Data * semitone;
76 LADSPA_Data * drylevel;
77 LADSPA_Data * wetlevel;
78 LADSPA_Data * latency;
79 LADSPA_Data * input;
80 LADSPA_Data * output;
81
82 LADSPA_Data * ringbuffer;
83 unsigned long buflen;
84 unsigned long pos;
85 LADSPA_Data phase;
86
87 unsigned long sample_rate;
88 LADSPA_Data run_adding_gain;
89 } Pitch;
90
91
92
93 /* Construct a new plugin instance. */
94 LADSPA_Handle
instantiate_Pitch(const LADSPA_Descriptor * Descriptor,unsigned long sample_rate)95 instantiate_Pitch(const LADSPA_Descriptor * Descriptor,
96 unsigned long sample_rate) {
97
98 LADSPA_Handle * ptr;
99
100 if ((ptr = malloc(sizeof(Pitch))) != NULL) {
101 ((Pitch *)ptr)->sample_rate = sample_rate;
102 ((Pitch *)ptr)->run_adding_gain = 1.0f;
103
104 if ((((Pitch *)ptr)->ringbuffer =
105 calloc(2 * PM_BUFLEN, sizeof(LADSPA_Data))) == NULL)
106 return NULL;
107 ((Pitch *)ptr)->buflen = 2 * PM_BUFLEN * sample_rate / 192000;
108 ((Pitch *)ptr)->pos = 0;
109
110 return ptr;
111 }
112 return NULL;
113 }
114
115
116 void
activate_Pitch(LADSPA_Handle Instance)117 activate_Pitch(LADSPA_Handle Instance) {
118
119 Pitch * ptr = (Pitch *)Instance;
120 unsigned long i;
121
122 for (i = 0; i < ptr->buflen; i++)
123 ptr->ringbuffer[i] = 0.0f;
124
125 ptr->phase = 0.0f;
126 }
127
128
129
130
131
132 /* Connect a port to a data location. */
133 void
connect_port_Pitch(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)134 connect_port_Pitch(LADSPA_Handle Instance,
135 unsigned long Port,
136 LADSPA_Data * DataLocation) {
137
138 Pitch * ptr = (Pitch *)Instance;
139
140 switch (Port) {
141 case RATE:
142 ptr->rate = DataLocation;
143 break;
144 case SEMITONE:
145 ptr->semitone = DataLocation;
146 break;
147 case DRYLEVEL:
148 ptr->drylevel = DataLocation;
149 break;
150 case WETLEVEL:
151 ptr->wetlevel = DataLocation;
152 break;
153 case LATENCY:
154 ptr->latency = DataLocation;
155 *(ptr->latency) = ptr->buflen / 2; /* IS THIS LEGAL? */
156 break;
157 case INPUT:
158 ptr->input = DataLocation;
159 break;
160 case OUTPUT:
161 ptr->output = DataLocation;
162 break;
163 }
164 }
165
166
167
168 void
run_Pitch(LADSPA_Handle Instance,unsigned long SampleCount)169 run_Pitch(LADSPA_Handle Instance,
170 unsigned long SampleCount) {
171
172 Pitch * ptr = (Pitch *)Instance;
173 LADSPA_Data * input = ptr->input;
174 LADSPA_Data * output = ptr->output;
175 LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
176 LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
177 LADSPA_Data buflen = ptr->buflen / 2.0f;
178 LADSPA_Data semitone = LIMIT(*(ptr->semitone),-12.0f,12.0f);
179 LADSPA_Data rate;
180 LADSPA_Data r;
181 LADSPA_Data depth;
182
183 unsigned long sample_index;
184 unsigned long sample_count = SampleCount;
185
186 LADSPA_Data in = 0.0f;
187 LADSPA_Data sign = 1.0f;
188 LADSPA_Data phase_0 = 0.0f;
189 LADSPA_Data phase_am_0 = 0.0f;
190 LADSPA_Data phase_1 = 0.0f;
191 LADSPA_Data phase_am_1 = 0.0f;
192 LADSPA_Data phase_2 = 0.0f;
193 LADSPA_Data phase_am_2 = 0.0f;
194 LADSPA_Data fpos_0 = 0.0f, fpos_1 = 0.0f, fpos_2 = 0.0f;
195 LADSPA_Data n_0 = 0.0f, n_1 = 0.0f, n_2 = 0.0f;
196 LADSPA_Data rem_0 = 0.0f, rem_1 = 0.0f, rem_2 = 0.0f;
197 LADSPA_Data sa_0, sb_0, sa_1, sb_1, sa_2, sb_2;
198
199
200 if (semitone == 0.0f)
201 rate = LIMIT(*(ptr->rate),-50.0f,100.0f);
202 else
203 rate = 100.0f * (powf(ROOT_12_2,semitone) - 1.0f);
204
205 r = -1.0f * ABS(rate);
206 depth = buflen * LIMIT(ABS(r) / 100.0f, 0.0f, 1.0f);
207
208
209 if (rate > 0.0f)
210 sign = -1.0f;
211
212 for (sample_index = 0; sample_index < sample_count; sample_index++) {
213
214 in = *(input++);
215
216 phase_0 = COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate + ptr->phase;
217 while (phase_0 >= COS_TABLE_SIZE)
218 phase_0 -= COS_TABLE_SIZE;
219 phase_am_0 = phase_0 + COS_TABLE_SIZE/2;
220 while (phase_am_0 >= COS_TABLE_SIZE)
221 phase_am_0 -= COS_TABLE_SIZE;
222
223 phase_1 = phase_0 + COS_TABLE_SIZE/3.0f;
224 while (phase_1 >= COS_TABLE_SIZE)
225 phase_1 -= COS_TABLE_SIZE;
226 phase_am_1 = phase_1 + COS_TABLE_SIZE/2;
227 while (phase_am_1 >= COS_TABLE_SIZE)
228 phase_am_1 -= COS_TABLE_SIZE;
229
230 phase_2 = phase_0 + 2.0f*COS_TABLE_SIZE/3.0f;
231 while (phase_2 >= COS_TABLE_SIZE)
232 phase_2 -= COS_TABLE_SIZE;
233 phase_am_2 = phase_2 + COS_TABLE_SIZE/2;
234 while (phase_am_2 >= COS_TABLE_SIZE)
235 phase_am_2 -= COS_TABLE_SIZE;
236
237 push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos));
238
239 fpos_0 = depth * (1.0f - sign * (2.0f * phase_0 / COS_TABLE_SIZE - 1.0f));
240 n_0 = floorf(fpos_0);
241 rem_0 = fpos_0 - n_0;
242
243 fpos_1 = depth * (1.0f - sign * (2.0f * phase_1 / COS_TABLE_SIZE - 1.0f));
244 n_1 = floorf(fpos_1);
245 rem_1 = fpos_1 - n_1;
246
247 fpos_2 = depth * (1.0f - sign * (2.0f * phase_2 / COS_TABLE_SIZE - 1.0f));
248 n_2 = floorf(fpos_2);
249 rem_2 = fpos_2 - n_2;
250
251 sa_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0);
252 sb_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0 + 1);
253
254 sa_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1);
255 sb_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1 + 1);
256
257 sa_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2);
258 sb_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2 + 1);
259
260 *(output++) =
261 wetlevel *
262 ((1.0f + cos_table[(unsigned long) phase_am_0]) *
263 ((1 - rem_0) * sa_0 + rem_0 * sb_0) +
264 (1.0f + cos_table[(unsigned long) phase_am_1]) *
265 ((1 - rem_1) * sa_1 + rem_1 * sb_1) +
266 (1.0f + cos_table[(unsigned long) phase_am_2]) *
267 ((1 - rem_2) * sa_2 + rem_2 * sb_2)) +
268 drylevel *
269 read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) depth);
270
271 }
272
273 ptr->phase += COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate;
274 while (ptr->phase >= COS_TABLE_SIZE)
275 ptr->phase -= COS_TABLE_SIZE;
276
277 *(ptr->latency) = buflen - (unsigned long) depth;
278 }
279
280
281
282 void
set_run_adding_gain_Pitch(LADSPA_Handle Instance,LADSPA_Data gain)283 set_run_adding_gain_Pitch(LADSPA_Handle Instance, LADSPA_Data gain) {
284
285 Pitch * ptr = (Pitch *)Instance;
286
287 ptr->run_adding_gain = gain;
288 }
289
290
291
292 void
run_adding_Pitch(LADSPA_Handle Instance,unsigned long SampleCount)293 run_adding_Pitch(LADSPA_Handle Instance,
294 unsigned long SampleCount) {
295
296 Pitch * ptr = (Pitch *)Instance;
297 LADSPA_Data * input = ptr->input;
298 LADSPA_Data * output = ptr->output;
299 LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
300 LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
301 LADSPA_Data buflen = ptr->buflen / 2.0f;
302 LADSPA_Data semitone = LIMIT(*(ptr->semitone),-12.0f,12.0f);
303 LADSPA_Data rate;
304 LADSPA_Data r;
305 LADSPA_Data depth;
306
307 unsigned long sample_index;
308 unsigned long sample_count = SampleCount;
309
310 LADSPA_Data in = 0.0f;
311 LADSPA_Data sign = 1.0f;
312 LADSPA_Data phase_0 = 0.0f;
313 LADSPA_Data phase_am_0 = 0.0f;
314 LADSPA_Data phase_1 = 0.0f;
315 LADSPA_Data phase_am_1 = 0.0f;
316 LADSPA_Data phase_2 = 0.0f;
317 LADSPA_Data phase_am_2 = 0.0f;
318 LADSPA_Data fpos_0 = 0.0f, fpos_1 = 0.0f, fpos_2 = 0.0f;
319 LADSPA_Data n_0 = 0.0f, n_1 = 0.0f, n_2 = 0.0f;
320 LADSPA_Data rem_0 = 0.0f, rem_1 = 0.0f, rem_2 = 0.0f;
321 LADSPA_Data sa_0, sb_0, sa_1, sb_1, sa_2, sb_2;
322
323
324 if (semitone == 0.0f)
325 rate = LIMIT(*(ptr->rate),-50.0f,100.0f);
326 else
327 rate = 100.0f * (powf(ROOT_12_2,semitone) - 1.0f);
328
329 r = -1.0f * ABS(rate);
330 depth = buflen * LIMIT(ABS(r) / 100.0f, 0.0f, 1.0f);
331
332
333 if (rate > 0.0f)
334 sign = -1.0f;
335
336 for (sample_index = 0; sample_index < sample_count; sample_index++) {
337
338 in = *(input++);
339
340 phase_0 = COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate + ptr->phase;
341 while (phase_0 >= COS_TABLE_SIZE)
342 phase_0 -= COS_TABLE_SIZE;
343 phase_am_0 = phase_0 + COS_TABLE_SIZE/2;
344 while (phase_am_0 >= COS_TABLE_SIZE)
345 phase_am_0 -= COS_TABLE_SIZE;
346
347 phase_1 = phase_0 + COS_TABLE_SIZE/3.0f;
348 while (phase_1 >= COS_TABLE_SIZE)
349 phase_1 -= COS_TABLE_SIZE;
350 phase_am_1 = phase_1 + COS_TABLE_SIZE/2;
351 while (phase_am_1 >= COS_TABLE_SIZE)
352 phase_am_1 -= COS_TABLE_SIZE;
353
354 phase_2 = phase_0 + 2.0f*COS_TABLE_SIZE/3.0f;
355 while (phase_2 >= COS_TABLE_SIZE)
356 phase_2 -= COS_TABLE_SIZE;
357 phase_am_2 = phase_2 + COS_TABLE_SIZE/2;
358 while (phase_am_2 >= COS_TABLE_SIZE)
359 phase_am_2 -= COS_TABLE_SIZE;
360
361 push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos));
362
363 fpos_0 = depth * (1.0f - sign * (2.0f * phase_0 / COS_TABLE_SIZE - 1.0f));
364 n_0 = floorf(fpos_0);
365 rem_0 = fpos_0 - n_0;
366
367 fpos_1 = depth * (1.0f - sign * (2.0f * phase_1 / COS_TABLE_SIZE - 1.0f));
368 n_1 = floorf(fpos_1);
369 rem_1 = fpos_1 - n_1;
370
371 fpos_2 = depth * (1.0f - sign * (2.0f * phase_2 / COS_TABLE_SIZE - 1.0f));
372 n_2 = floorf(fpos_2);
373 rem_2 = fpos_2 - n_2;
374
375 sa_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0);
376 sb_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0 + 1);
377
378 sa_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1);
379 sb_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1 + 1);
380
381 sa_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2);
382 sb_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2 + 1);
383
384 *(output++) += ptr->run_adding_gain *
385 wetlevel *
386 ((1.0f + cos_table[(unsigned long) phase_am_0]) *
387 ((1 - rem_0) * sa_0 + rem_0 * sb_0) +
388 (1.0f + cos_table[(unsigned long) phase_am_1]) *
389 ((1 - rem_1) * sa_1 + rem_1 * sb_1) +
390 (1.0f + cos_table[(unsigned long) phase_am_2]) *
391 ((1 - rem_2) * sa_2 + rem_2 * sb_2)) +
392 drylevel *
393 read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) depth);
394
395 }
396
397 ptr->phase += COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate;
398 while (ptr->phase >= COS_TABLE_SIZE)
399 ptr->phase -= COS_TABLE_SIZE;
400
401 *(ptr->latency) = buflen - (unsigned long) depth;
402 }
403
404
405
406 /* Throw away a Pitch effect instance. */
407 void
cleanup_Pitch(LADSPA_Handle Instance)408 cleanup_Pitch(LADSPA_Handle Instance) {
409
410 Pitch * ptr = (Pitch *)Instance;
411 free(ptr->ringbuffer);
412 free(Instance);
413 }
414
415
416
417 LADSPA_Descriptor * mono_descriptor = NULL;
418
419
420
421 /* _init() is called automatically when the plugin library is first
422 loaded. */
423 void
_init()424 _init() {
425
426 int i;
427 char ** port_names;
428 LADSPA_PortDescriptor * port_descriptors;
429 LADSPA_PortRangeHint * port_range_hints;
430
431 if ((mono_descriptor =
432 (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
433 exit(1);
434
435 for (i = 0; i < COS_TABLE_SIZE; i++)
436 cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE);
437
438
439 mono_descriptor->UniqueID = ID_MONO;
440 mono_descriptor->Label = strdup("tap_pitch");
441 mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
442 mono_descriptor->Name = strdup("TAP Pitch Shifter");
443 mono_descriptor->Maker = strdup("Tom Szilagyi");
444 mono_descriptor->Copyright = strdup("GPL");
445 mono_descriptor->PortCount = PORTCOUNT_MONO;
446
447 if ((port_descriptors =
448 (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
449 exit(1);
450
451 mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
452 port_descriptors[RATE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
453 port_descriptors[SEMITONE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
454 port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
455 port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
456 port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
457 port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
458 port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
459
460 if ((port_names =
461 (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
462 exit(1);
463
464 mono_descriptor->PortNames = (const char **)port_names;
465 port_names[SEMITONE] = strdup("Semitone Shift");
466 port_names[RATE] = strdup("Rate Shift [%]");
467 port_names[DRYLEVEL] = strdup("Dry Level [dB]");
468 port_names[WETLEVEL] = strdup("Wet Level [dB]");
469 port_names[LATENCY] = strdup("latency");
470 port_names[INPUT] = strdup("Input");
471 port_names[OUTPUT] = strdup("Output");
472
473 if ((port_range_hints =
474 ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
475 exit(1);
476
477 mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints;
478 port_range_hints[RATE].HintDescriptor =
479 (LADSPA_HINT_BOUNDED_BELOW |
480 LADSPA_HINT_BOUNDED_ABOVE |
481 LADSPA_HINT_DEFAULT_0);
482 port_range_hints[SEMITONE].HintDescriptor =
483 (LADSPA_HINT_BOUNDED_BELOW |
484 LADSPA_HINT_BOUNDED_ABOVE |
485 LADSPA_HINT_DEFAULT_0);
486 port_range_hints[DRYLEVEL].HintDescriptor =
487 (LADSPA_HINT_BOUNDED_BELOW |
488 LADSPA_HINT_BOUNDED_ABOVE |
489 LADSPA_HINT_DEFAULT_MINIMUM);
490 port_range_hints[WETLEVEL].HintDescriptor =
491 (LADSPA_HINT_BOUNDED_BELOW |
492 LADSPA_HINT_BOUNDED_ABOVE |
493 LADSPA_HINT_DEFAULT_0);
494 port_range_hints[LATENCY].HintDescriptor =
495 (LADSPA_HINT_BOUNDED_BELOW |
496 LADSPA_HINT_BOUNDED_ABOVE |
497 LADSPA_HINT_DEFAULT_MAXIMUM);
498 port_range_hints[RATE].LowerBound = -50.0f;
499 port_range_hints[RATE].UpperBound = 100.0f;
500 port_range_hints[SEMITONE].LowerBound = -12.0f;
501 port_range_hints[SEMITONE].UpperBound = 12.0f;
502 port_range_hints[DRYLEVEL].LowerBound = -90.0f;
503 port_range_hints[DRYLEVEL].UpperBound = 20.0f;
504 port_range_hints[WETLEVEL].LowerBound = -90.0f;
505 port_range_hints[WETLEVEL].UpperBound = 20.0f;
506 port_range_hints[LATENCY].LowerBound = 0;
507 port_range_hints[LATENCY].UpperBound = PM_BUFLEN;
508 port_range_hints[INPUT].HintDescriptor = 0;
509 port_range_hints[OUTPUT].HintDescriptor = 0;
510 mono_descriptor->instantiate = instantiate_Pitch;
511 mono_descriptor->connect_port = connect_port_Pitch;
512 mono_descriptor->activate = activate_Pitch;
513 mono_descriptor->run = run_Pitch;
514 mono_descriptor->run_adding = run_adding_Pitch;
515 mono_descriptor->set_run_adding_gain = set_run_adding_gain_Pitch;
516 mono_descriptor->deactivate = NULL;
517 mono_descriptor->cleanup = cleanup_Pitch;
518 }
519
520
521 void
delete_descriptor(LADSPA_Descriptor * descriptor)522 delete_descriptor(LADSPA_Descriptor * descriptor) {
523 unsigned long index;
524 if (descriptor) {
525 free((char *)descriptor->Label);
526 free((char *)descriptor->Name);
527 free((char *)descriptor->Maker);
528 free((char *)descriptor->Copyright);
529 free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
530 for (index = 0; index < descriptor->PortCount; index++)
531 free((char *)(descriptor->PortNames[index]));
532 free((char **)descriptor->PortNames);
533 free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
534 free(descriptor);
535 }
536 }
537
538
539 /* _fini() is called automatically when the library is unloaded. */
540 void
_fini()541 _fini() {
542 delete_descriptor(mono_descriptor);
543 }
544
545
546 /* Return a descriptor of the requested plugin type. */
547 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)548 ladspa_descriptor(unsigned long Index) {
549
550 switch (Index) {
551 case 0:
552 return mono_descriptor;
553 default:
554 return NULL;
555 }
556 }
557