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_echo.c,v 1.7 2004/12/06 09:32:41 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 /* The Unique ID of the plugin: */
31
32 #define ID_STEREO 2143
33
34 /* The port numbers for the plugin: */
35
36 #define DELAYTIME_L 0
37 #define FEEDBACK_L 1
38 #define DELAYTIME_R 2
39 #define FEEDBACK_R 3
40 #define STRENGTH_L 4
41 #define STRENGTH_R 5
42 #define DRYLEVEL 6
43 #define MODE 7
44 #define HAAS 8
45 #define REV_OUTCH 9
46
47 #define INPUT_L 10
48 #define OUTPUT_L 11
49 #define INPUT_R 12
50 #define OUTPUT_R 13
51
52 /* Total number of ports */
53
54 #define PORTCOUNT_STEREO 14
55
56
57 /* Maximum delay (ms) */
58
59 #define MAX_DELAY 2000
60
61
62 /* The structure used to hold port connection information and state */
63
64 typedef struct {
65 LADSPA_Data * delaytime_L;
66 LADSPA_Data * delaytime_R;
67 LADSPA_Data * feedback_L;
68 LADSPA_Data * feedback_R;
69 LADSPA_Data * strength_L;
70 LADSPA_Data * strength_R;
71 LADSPA_Data * drylevel;
72 LADSPA_Data * mode;
73 LADSPA_Data * haas;
74 LADSPA_Data * rev_outch;
75
76 LADSPA_Data * input_L;
77 LADSPA_Data * output_L;
78 LADSPA_Data * input_R;
79 LADSPA_Data * output_R;
80
81 unsigned long sample_rate;
82 LADSPA_Data mpx_out_L;
83 LADSPA_Data mpx_out_R;
84
85 LADSPA_Data * ringbuffer_L;
86 LADSPA_Data * ringbuffer_R;
87 unsigned long * buffer_pos_L;
88 unsigned long * buffer_pos_R;
89
90 LADSPA_Data run_adding_gain;
91 } Echo;
92
93
94
95
96 /* Construct a new plugin instance. */
97 LADSPA_Handle
instantiate_Echo(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)98 instantiate_Echo(const LADSPA_Descriptor * Descriptor,
99 unsigned long SampleRate) {
100
101 LADSPA_Handle * ptr;
102
103 if ((ptr = malloc(sizeof(Echo))) != NULL) {
104 ((Echo *)ptr)->sample_rate = SampleRate;
105 ((Echo *)ptr)->run_adding_gain = 1.0f;
106
107 /* allocate memory for ringbuffers and related dynamic vars */
108 if ((((Echo *)ptr)->ringbuffer_L =
109 calloc(MAX_DELAY * ((Echo *)ptr)->sample_rate / 1000,
110 sizeof(LADSPA_Data))) == NULL)
111 exit(1);
112 if ((((Echo *)ptr)->ringbuffer_R =
113 calloc(MAX_DELAY * ((Echo *)ptr)->sample_rate / 1000,
114 sizeof(LADSPA_Data))) == NULL)
115 exit(1);
116 if ((((Echo *)ptr)->buffer_pos_L = calloc(1, sizeof(unsigned long))) == NULL)
117 exit(1);
118 if ((((Echo *)ptr)->buffer_pos_R = calloc(1, sizeof(unsigned long))) == NULL)
119 exit(1);
120
121 *(((Echo *)ptr)->buffer_pos_L) = 0;
122 *(((Echo *)ptr)->buffer_pos_R) = 0;
123
124 return ptr;
125 }
126
127 return NULL;
128 }
129
130
131 /* activate a plugin instance */
132 void
activate_Echo(LADSPA_Handle Instance)133 activate_Echo(LADSPA_Handle Instance) {
134
135 Echo * ptr = (Echo *)Instance;
136 int i;
137
138 ptr->mpx_out_L = 0;
139 ptr->mpx_out_R = 0;
140
141 *(ptr->buffer_pos_L) = 0;
142 *(ptr->buffer_pos_R) = 0;
143
144 for (i = 0; i < MAX_DELAY * ptr->sample_rate / 1000; i++) {
145 ptr->ringbuffer_L[i] = 0.0f;
146 ptr->ringbuffer_R[i] = 0.0f;
147 }
148 }
149
150
151 /* Connect a port to a data location. */
152 void
connect_port_Echo(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)153 connect_port_Echo(LADSPA_Handle Instance,
154 unsigned long Port,
155 LADSPA_Data * DataLocation) {
156
157 Echo * ptr;
158
159 ptr = (Echo *)Instance;
160 switch (Port) {
161 case DELAYTIME_L:
162 ptr->delaytime_L = DataLocation;
163 break;
164 case DELAYTIME_R:
165 ptr->delaytime_R = DataLocation;
166 break;
167 case FEEDBACK_L:
168 ptr->feedback_L = DataLocation;
169 break;
170 case FEEDBACK_R:
171 ptr->feedback_R = DataLocation;
172 break;
173 case STRENGTH_L:
174 ptr->strength_L = DataLocation;
175 break;
176 case STRENGTH_R:
177 ptr->strength_R = DataLocation;
178 break;
179 case MODE:
180 ptr->mode = DataLocation;
181 break;
182 case HAAS:
183 ptr->haas = DataLocation;
184 break;
185 case REV_OUTCH:
186 ptr->rev_outch = DataLocation;
187 break;
188 case DRYLEVEL:
189 ptr->drylevel = DataLocation;
190 break;
191 case INPUT_L:
192 ptr->input_L = DataLocation;
193 break;
194 case OUTPUT_L:
195 ptr->output_L = DataLocation;
196 break;
197 case INPUT_R:
198 ptr->input_R = DataLocation;
199 break;
200 case OUTPUT_R:
201 ptr->output_R = DataLocation;
202 break;
203 }
204 }
205
206
207 #define EPS 0.00000001f
208
209 static inline float
M(float x)210 M(float x) {
211
212 if ((x > EPS) || (x < -EPS))
213 return x;
214 else
215 return 0.0f;
216 }
217
218 void
run_Echo(LADSPA_Handle Instance,unsigned long SampleCount)219 run_Echo(LADSPA_Handle Instance,
220 unsigned long SampleCount) {
221
222 Echo * ptr;
223 unsigned long sample_index;
224
225 LADSPA_Data delaytime_L;
226 LADSPA_Data delaytime_R;
227 LADSPA_Data feedback_L;
228 LADSPA_Data feedback_R;
229 LADSPA_Data strength_L;
230 LADSPA_Data strength_R;
231 LADSPA_Data drylevel;
232 LADSPA_Data mode;
233 LADSPA_Data haas;
234 LADSPA_Data rev_outch;
235
236 LADSPA_Data * input_L;
237 LADSPA_Data * output_L;
238 LADSPA_Data * input_R;
239 LADSPA_Data * output_R;
240
241 unsigned long sample_rate;
242 unsigned long buflen_L;
243 unsigned long buflen_R;
244
245 LADSPA_Data out_L = 0;
246 LADSPA_Data out_R = 0;
247 LADSPA_Data in_L = 0;
248 LADSPA_Data in_R = 0;
249
250 ptr = (Echo *)Instance;
251
252 delaytime_L = LIMIT(*(ptr->delaytime_L),0.0f,2000.0f);
253 delaytime_R = LIMIT(*(ptr->delaytime_R),0.0f,2000.0f);
254 feedback_L = LIMIT(*(ptr->feedback_L) / 100.0, 0.0f, 100.0f);
255 feedback_R = LIMIT(*(ptr->feedback_R) / 100.0, 0.0f, 100.0f);
256 strength_L = db2lin(LIMIT(*(ptr->strength_L),-70.0f,10.0f));
257 strength_R = db2lin(LIMIT(*(ptr->strength_R),-70.0f,10.0f));
258 drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f));
259 mode = LIMIT(*(ptr->mode),-2.0f,2.0f);
260 haas = LIMIT(*(ptr->haas),-2.0f,2.0f);
261 rev_outch = LIMIT(*(ptr->rev_outch),-2.0f,2.0f);
262
263 input_L = ptr->input_L;
264 output_L = ptr->output_L;
265 input_R = ptr->input_R;
266 output_R = ptr->output_R;
267
268 sample_rate = ptr->sample_rate;
269 buflen_L = delaytime_L * sample_rate / 1000;
270 buflen_R = delaytime_R * sample_rate / 1000;
271
272
273 for (sample_index = 0; sample_index < SampleCount; sample_index++) {
274
275 in_L = *(input_L++);
276 in_R = *(input_R++);
277
278 out_L = in_L * drylevel + ptr->mpx_out_L * strength_L;
279 out_R = in_R * drylevel + ptr->mpx_out_R * strength_R;
280
281 if (haas > 0.0f)
282 in_R = 0.0f;
283
284 if (mode <= 0.0f) {
285 ptr->mpx_out_L =
286 M(push_buffer(in_L + ptr->mpx_out_L * feedback_L,
287 ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L));
288 ptr->mpx_out_R =
289 M(push_buffer(in_R + ptr->mpx_out_R * feedback_R,
290 ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R));
291 } else {
292 ptr->mpx_out_R =
293 M(push_buffer(in_L + ptr->mpx_out_L * feedback_L,
294 ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L));
295 ptr->mpx_out_L =
296 M(push_buffer(in_R + ptr->mpx_out_R * feedback_R,
297 ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R));
298 }
299
300 if (rev_outch <= 0.0f) {
301 *(output_L++) = out_L;
302 *(output_R++) = out_R;
303 } else {
304 *(output_L++) = out_R;
305 *(output_R++) = out_L;
306 }
307 }
308 }
309
310
311
312
313
314 void
set_run_adding_gain(LADSPA_Handle Instance,LADSPA_Data gain)315 set_run_adding_gain(LADSPA_Handle Instance, LADSPA_Data gain){
316
317 Echo * ptr;
318
319 ptr = (Echo *)Instance;
320
321 ptr->run_adding_gain = gain;
322 }
323
324
325 void
run_adding_gain_Echo(LADSPA_Handle Instance,unsigned long SampleCount)326 run_adding_gain_Echo(LADSPA_Handle Instance,
327 unsigned long SampleCount) {
328
329 Echo * ptr;
330 unsigned long sample_index;
331
332 LADSPA_Data delaytime_L;
333 LADSPA_Data delaytime_R;
334 LADSPA_Data feedback_L;
335 LADSPA_Data feedback_R;
336 LADSPA_Data strength_L;
337 LADSPA_Data strength_R;
338 LADSPA_Data drylevel;
339 LADSPA_Data mode;
340 LADSPA_Data haas;
341 LADSPA_Data rev_outch;
342
343 LADSPA_Data * input_L;
344 LADSPA_Data * output_L;
345 LADSPA_Data * input_R;
346 LADSPA_Data * output_R;
347
348 unsigned long sample_rate;
349 unsigned long buflen_L;
350 unsigned long buflen_R;
351
352 LADSPA_Data out_L = 0;
353 LADSPA_Data out_R = 0;
354 LADSPA_Data in_L = 0;
355 LADSPA_Data in_R = 0;
356
357 ptr = (Echo *)Instance;
358
359 delaytime_L = LIMIT(*(ptr->delaytime_L),0.0f,2000.0f);
360 delaytime_R = LIMIT(*(ptr->delaytime_R),0.0f,2000.0f);
361 feedback_L = LIMIT(*(ptr->feedback_L) / 100.0, 0.0f, 100.0f);
362 feedback_R = LIMIT(*(ptr->feedback_R) / 100.0, 0.0f, 100.0f);
363 strength_L = db2lin(LIMIT(*(ptr->strength_L),-70.0f,10.0f));
364 strength_R = db2lin(LIMIT(*(ptr->strength_R),-70.0f,10.0f));
365 drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f));
366 mode = LIMIT(*(ptr->mode),-2.0f,2.0f);
367 haas = LIMIT(*(ptr->haas),-2.0f,2.0f);
368 rev_outch = LIMIT(*(ptr->rev_outch),-2.0f,2.0f);
369
370 input_L = ptr->input_L;
371 output_L = ptr->output_L;
372 input_R = ptr->input_R;
373 output_R = ptr->output_R;
374
375 sample_rate = ptr->sample_rate;
376 buflen_L = delaytime_L * sample_rate / 1000;
377 buflen_R = delaytime_R * sample_rate / 1000;
378
379
380 for (sample_index = 0; sample_index < SampleCount; sample_index++) {
381
382 in_L = *(input_L++);
383 in_R = *(input_R++);
384
385 out_L = in_L * drylevel + ptr->mpx_out_L * strength_L;
386 out_R = in_R * drylevel + ptr->mpx_out_R * strength_R;
387
388 if (haas > 0.0f)
389 in_R = 0.0f;
390
391 if (mode <= 0.0f) {
392 ptr->mpx_out_L =
393 M(push_buffer(in_L + ptr->mpx_out_L * feedback_L,
394 ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L));
395 ptr->mpx_out_R =
396 M(push_buffer(in_R + ptr->mpx_out_R * feedback_R,
397 ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R));
398 } else {
399 ptr->mpx_out_R =
400 M(push_buffer(in_L + ptr->mpx_out_L * feedback_L,
401 ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L));
402 ptr->mpx_out_L =
403 M(push_buffer(in_R + ptr->mpx_out_R * feedback_R,
404 ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R));
405 }
406
407 if (rev_outch <= 0.0f) {
408 *(output_L++) += out_L * ptr->run_adding_gain;
409 *(output_R++) += out_R * ptr->run_adding_gain;
410 } else {
411 *(output_L++) += out_R * ptr->run_adding_gain;
412 *(output_R++) += out_L * ptr->run_adding_gain;
413 }
414 }
415 }
416
417
418
419 /* Throw away an Echo effect instance. */
420 void
cleanup_Echo(LADSPA_Handle Instance)421 cleanup_Echo(LADSPA_Handle Instance) {
422
423 Echo * ptr = (Echo *)Instance;
424
425 free(ptr->ringbuffer_L);
426 free(ptr->ringbuffer_R);
427 free(ptr->buffer_pos_L);
428 free(ptr->buffer_pos_R);
429
430 free(Instance);
431 }
432
433
434
435 LADSPA_Descriptor * stereo_descriptor = NULL;
436
437
438
439 /* _init() is called automatically when the plugin library is first
440 loaded. */
441 void
_init()442 _init() {
443
444 char ** port_names;
445 LADSPA_PortDescriptor * port_descriptors;
446 LADSPA_PortRangeHint * port_range_hints;
447
448 if ((stereo_descriptor =
449 (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
450 exit(1);
451
452
453 /* init the stereo Echo */
454
455 stereo_descriptor->UniqueID = ID_STEREO;
456 stereo_descriptor->Label = strdup("tap_stereo_echo");
457 stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
458 stereo_descriptor->Name = strdup("TAP Stereo Echo");
459 stereo_descriptor->Maker = strdup("Tom Szilagyi");
460 stereo_descriptor->Copyright = strdup("GPL");
461 stereo_descriptor->PortCount = PORTCOUNT_STEREO;
462
463 if ((port_descriptors =
464 (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL)
465 exit(1);
466
467 stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
468 port_descriptors[DELAYTIME_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
469 port_descriptors[DELAYTIME_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
470 port_descriptors[FEEDBACK_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
471 port_descriptors[FEEDBACK_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
472 port_descriptors[STRENGTH_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
473 port_descriptors[STRENGTH_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
474 port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
475 port_descriptors[MODE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
476 port_descriptors[HAAS] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
477 port_descriptors[REV_OUTCH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
478
479 port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
480 port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
481 port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
482 port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
483
484 if ((port_names =
485 (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL)
486 exit(1);
487
488 stereo_descriptor->PortNames = (const char **)port_names;
489
490 port_names[DELAYTIME_L] = strdup("L Delay [ms]");
491 port_names[DELAYTIME_R] = strdup("R/Haas Delay [ms]");
492 port_names[FEEDBACK_L] = strdup("L Feedback [%]");
493 port_names[FEEDBACK_R] = strdup("R/Haas Feedback [%]");
494 port_names[STRENGTH_L] = strdup("L Echo Level [dB]");
495 port_names[STRENGTH_R] = strdup("R Echo Level [dB]");
496 port_names[DRYLEVEL] = strdup("Dry Level [dB]");
497 port_names[MODE] = strdup("Cross Mode");
498 port_names[HAAS] = strdup("Haas Effect");
499 port_names[REV_OUTCH] = strdup("Swap Outputs");
500
501 port_names[INPUT_L] = strdup("Input Left");
502 port_names[OUTPUT_L] = strdup("Output Left");
503 port_names[INPUT_R] = strdup("Input Right");
504 port_names[OUTPUT_R] = strdup("Output Right");
505
506 if ((port_range_hints =
507 ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL)
508 exit(1);
509
510 stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints;
511
512 port_range_hints[DELAYTIME_L].HintDescriptor =
513 (LADSPA_HINT_BOUNDED_BELOW |
514 LADSPA_HINT_BOUNDED_ABOVE |
515 LADSPA_HINT_DEFAULT_100);
516 port_range_hints[DELAYTIME_L].LowerBound = 0;
517 port_range_hints[DELAYTIME_L].UpperBound = MAX_DELAY;
518
519 port_range_hints[DELAYTIME_R].HintDescriptor =
520 (LADSPA_HINT_BOUNDED_BELOW |
521 LADSPA_HINT_BOUNDED_ABOVE |
522 LADSPA_HINT_DEFAULT_100);
523 port_range_hints[DELAYTIME_R].LowerBound = 0;
524 port_range_hints[DELAYTIME_R].UpperBound = MAX_DELAY;
525
526 port_range_hints[FEEDBACK_L].HintDescriptor =
527 (LADSPA_HINT_BOUNDED_BELOW |
528 LADSPA_HINT_BOUNDED_ABOVE |
529 LADSPA_HINT_DEFAULT_0);
530 port_range_hints[FEEDBACK_L].LowerBound = 0;
531 port_range_hints[FEEDBACK_L].UpperBound = 100;
532
533 port_range_hints[FEEDBACK_R].HintDescriptor =
534 (LADSPA_HINT_BOUNDED_BELOW |
535 LADSPA_HINT_BOUNDED_ABOVE |
536 LADSPA_HINT_DEFAULT_0);
537 port_range_hints[FEEDBACK_R].LowerBound = 0;
538 port_range_hints[FEEDBACK_R].UpperBound = 100;
539
540 port_range_hints[STRENGTH_L].HintDescriptor =
541 (LADSPA_HINT_BOUNDED_BELOW |
542 LADSPA_HINT_BOUNDED_ABOVE |
543 LADSPA_HINT_DEFAULT_0);
544 port_range_hints[STRENGTH_L].LowerBound = -70;
545 port_range_hints[STRENGTH_L].UpperBound = 10;
546
547 port_range_hints[STRENGTH_R].HintDescriptor =
548 (LADSPA_HINT_BOUNDED_BELOW |
549 LADSPA_HINT_BOUNDED_ABOVE |
550 LADSPA_HINT_DEFAULT_0);
551 port_range_hints[STRENGTH_R].LowerBound = -70;
552 port_range_hints[STRENGTH_R].UpperBound = 10;
553
554 port_range_hints[MODE].HintDescriptor =
555 (LADSPA_HINT_TOGGLED |
556 LADSPA_HINT_DEFAULT_0);
557
558 port_range_hints[HAAS].HintDescriptor =
559 (LADSPA_HINT_TOGGLED |
560 LADSPA_HINT_DEFAULT_0);
561
562 port_range_hints[REV_OUTCH].HintDescriptor =
563 (LADSPA_HINT_TOGGLED |
564 LADSPA_HINT_DEFAULT_0);
565
566 port_range_hints[DRYLEVEL].HintDescriptor =
567 (LADSPA_HINT_BOUNDED_BELOW |
568 LADSPA_HINT_BOUNDED_ABOVE |
569 LADSPA_HINT_DEFAULT_0);
570 port_range_hints[DRYLEVEL].LowerBound = -70;
571 port_range_hints[DRYLEVEL].UpperBound = 10;
572
573
574 port_range_hints[INPUT_L].HintDescriptor = 0;
575 port_range_hints[OUTPUT_L].HintDescriptor = 0;
576 port_range_hints[INPUT_R].HintDescriptor = 0;
577 port_range_hints[OUTPUT_R].HintDescriptor = 0;
578
579
580 stereo_descriptor->instantiate = instantiate_Echo;
581 stereo_descriptor->connect_port = connect_port_Echo;
582 stereo_descriptor->activate = activate_Echo;
583 stereo_descriptor->run = run_Echo;
584 stereo_descriptor->run_adding = run_adding_gain_Echo;
585 stereo_descriptor->set_run_adding_gain = set_run_adding_gain;
586 stereo_descriptor->deactivate = NULL;
587 stereo_descriptor->cleanup = cleanup_Echo;
588
589 }
590
591
592 void
delete_descriptor(LADSPA_Descriptor * descriptor)593 delete_descriptor(LADSPA_Descriptor * descriptor) {
594 unsigned long index;
595 if (descriptor) {
596 free((char *)descriptor->Label);
597 free((char *)descriptor->Name);
598 free((char *)descriptor->Maker);
599 free((char *)descriptor->Copyright);
600 free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
601 for (index = 0; index < descriptor->PortCount; index++)
602 free((char *)(descriptor->PortNames[index]));
603 free((char **)descriptor->PortNames);
604 free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
605 free(descriptor);
606 }
607 }
608
609
610 /* _fini() is called automatically when the library is unloaded. */
611 void
_fini()612 _fini() {
613 delete_descriptor(stereo_descriptor);
614 }
615
616
617 /* Return a descriptor of the requested plugin type. */
618
619 const
620 LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)621 ladspa_descriptor(unsigned long Index) {
622
623 switch (Index) {
624 case 0:
625 return stereo_descriptor;
626 default:
627 return NULL;
628 }
629 }
630