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_chorusflanger.c,v 1.3 2004/08/17 09:15:21 tszilagyi Exp $
19 */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <time.h>
27
28 #include "ladspa.h"
29 #include "tap_utils.h"
30
31
32 /* The Unique ID of the plugin: */
33
34 #define ID_STEREO 2159
35
36 /* The port numbers for the plugin: */
37
38 #define FREQ 0
39 #define PHASE 1
40 #define DEPTH 2
41 #define DELAY 3
42 #define CONTOUR 4
43 #define DRYLEVEL 5
44 #define WETLEVEL 6
45 #define INPUT_L 7
46 #define INPUT_R 8
47 #define OUTPUT_L 9
48 #define OUTPUT_R 10
49
50 /* Total number of ports */
51 #define PORTCOUNT_STEREO 11
52
53
54 /*
55 * Largest buffer lengths needed (at 192 kHz).
56 * These are summed up to determine the size of *one* buffer per channel.
57 */
58 #define DEPTH_BUFLEN 450
59 #define DELAY_BUFLEN 19200
60
61 /* Max. frequency setting */
62 #define MAX_FREQ 5.0f
63
put_n(DB * db,DB_TXN * tid,int i)64 /* bandwidth of highpass filters (in octaves) */
65 #define HP_BW 1
66
67 /* cosine table for fast computations */
68 #define COS_TABLE_SIZE 1024
69 LADSPA_Data cos_table[COS_TABLE_SIZE];
70
71
72 /* The structure used to hold port connection information and state */
73 typedef struct {
74 LADSPA_Data * freq;
75 LADSPA_Data * phase;
76 LADSPA_Data * depth;
77 LADSPA_Data * delay;
78 LADSPA_Data * contour;
79 LADSPA_Data * drylevel;
80 LADSPA_Data * wetlevel;
del_n(DB * db,DB_TXN * tid,int i)81 LADSPA_Data * input_L;
82 LADSPA_Data * input_R;
83 LADSPA_Data * output_L;
84 LADSPA_Data * output_R;
85
86 LADSPA_Data * ring_L;
87 unsigned long buflen_L;
88 unsigned long pos_L;
89 LADSPA_Data * ring_R;
90 unsigned long buflen_R;
91 unsigned long pos_R;
92
93 biquad highpass_L;
94 biquad highpass_R;
95
96 float cm_phase;
97 float dm_phase;
98
99 unsigned long sample_rate;
100 LADSPA_Data run_adding_gain;
101 } ChorusFlanger;
102
103
104 /* Construct a new plugin instance. */
105 LADSPA_Handle
106 instantiate_ChorusFlanger(const LADSPA_Descriptor * Descriptor,
make_db(void)107 unsigned long sample_rate) {
108
109 LADSPA_Handle * ptr;
110
111 if ((ptr = malloc(sizeof(ChorusFlanger))) != NULL) {
112 ((ChorusFlanger *)ptr)->sample_rate = sample_rate;
113 ((ChorusFlanger *)ptr)->run_adding_gain = 1.0f;
114
115
116 if ((((ChorusFlanger *)ptr)->ring_L =
117 calloc((DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000,
118 sizeof(LADSPA_Data))) == NULL)
119 return NULL;
120 ((ChorusFlanger *)ptr)->buflen_L = (DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000;
121 ((ChorusFlanger *)ptr)->pos_L = 0;
122
123 if ((((ChorusFlanger *)ptr)->ring_R =
124 calloc((DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000,
125 sizeof(LADSPA_Data))) == NULL)
126 return NULL;
127 ((ChorusFlanger *)ptr)->buflen_R = (DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000;
128 ((ChorusFlanger *)ptr)->pos_R = 0;
129
130
131 ((ChorusFlanger *)ptr)->cm_phase = 0.0f;
132 ((ChorusFlanger *)ptr)->dm_phase = 0.0f;
133
134 return ptr;
135 }
136 return NULL;
137 }
138
139
140 void
141 activate_ChorusFlanger(LADSPA_Handle Instance) {
142
143 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
144 unsigned long i;
145
146 for (i = 0; i < (DEPTH_BUFLEN + DELAY_BUFLEN) * ptr->sample_rate / 192000; i++) {
147 ptr->ring_L[i] = 0.0f;
148 ptr->ring_R[i] = 0.0f;
149 }
150
151 biquad_init(&ptr->highpass_L);
152 biquad_init(&ptr->highpass_R);
153 }
154
155
156
157
158 /* Connect a port to a data location. */
159 void
test_main(int argc,char * const argv[])160 connect_port_ChorusFlanger(LADSPA_Handle Instance,
161 unsigned long Port,
162 LADSPA_Data * data) {
163
164 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
165
166 switch (Port) {
167 case FREQ:
168 ptr->freq = data;
169 break;
170 case PHASE:
171 ptr->phase = data;
172 break;
173 case DEPTH:
174 ptr->depth = data;
175 break;
176 case DELAY:
177 ptr->delay = data;
178 break;
179 case CONTOUR:
180 ptr->contour = data;
181 break;
182 case DRYLEVEL:
183 ptr->drylevel = data;
184 break;
185 case WETLEVEL:
186 ptr->wetlevel = data;
187 break;
188 case INPUT_L:
189 ptr->input_L = data;
190 break;
191 case INPUT_R:
192 ptr->input_R = data;
193 break;
194 case OUTPUT_L:
195 ptr->output_L = data;
196 break;
197 case OUTPUT_R:
198 ptr->output_R = data;
199 break;
200 }
201 }
202
203
204 void
205 run_ChorusFlanger(LADSPA_Handle Instance,
206 unsigned long SampleCount) {
207
208 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
209
210 LADSPA_Data freq = LIMIT(*(ptr->freq), 0.0f, MAX_FREQ);
211 LADSPA_Data phase = LIMIT(*(ptr->phase), 0.0f, 180.0f) / 180.0f;
212 LADSPA_Data depth = 100.0f * ptr->sample_rate / 44100.0f
213 * LIMIT(*(ptr->depth),0.0f,100.0f) / 100.0f;
214 LADSPA_Data delay = LIMIT(*(ptr->delay),0.0f,100.0f);
215 LADSPA_Data contour = LIMIT(*(ptr->contour), 20.0f, 20000.0f);
216 LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
217 LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
218 LADSPA_Data * input_L = ptr->input_L;
219 LADSPA_Data * input_R = ptr->input_R;
220 LADSPA_Data * output_L = ptr->output_L;
221 LADSPA_Data * output_R = ptr->output_R;
222
223 unsigned long sample_index;
224 unsigned long sample_count = SampleCount;
225
226 LADSPA_Data in_L = 0.0f;
227 LADSPA_Data in_R = 0.0f;
228 LADSPA_Data d_L = 0.0f;
229 LADSPA_Data d_R = 0.0f;
230 LADSPA_Data f_L = 0.0f;
231 LADSPA_Data f_R = 0.0f;
232 LADSPA_Data out_L = 0.0f;
233 LADSPA_Data out_R = 0.0f;
234
235 float phase_L = 0.0f;
236 float phase_R = 0.0f;
237 float fpos_L = 0.0f;
238 float fpos_R = 0.0f;
239 float n_L = 0.0f;
240 float n_R = 0.0f;
241 float rem_L = 0.0f;
242 float rem_R = 0.0f;
243 float s_a_L, s_a_R, s_b_L, s_b_R;
244
245 float d_pos = 0.0f;
246
247 if (delay < 1.0f)
248 delay = 1.0f;
249 delay = 100.0f - delay;
250
251 hp_set_params(&ptr->highpass_L, contour, HP_BW, ptr->sample_rate);
252 hp_set_params(&ptr->highpass_R, contour, HP_BW, ptr->sample_rate);
253
254 for (sample_index = 0; sample_index < sample_count; sample_index++) {
255
256 in_L = *(input_L++);
257 in_R = *(input_R++);
258
259 push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L));
260 push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R));
261
262 ptr->cm_phase += freq / ptr->sample_rate * COS_TABLE_SIZE;
263
264 while (ptr->cm_phase >= COS_TABLE_SIZE)
265 ptr->cm_phase -= COS_TABLE_SIZE;
266
267 ptr->dm_phase = phase * COS_TABLE_SIZE / 2.0f;
268
269 phase_L = ptr->cm_phase;
270 phase_R = ptr->cm_phase + ptr->dm_phase;
271 while (phase_R >= COS_TABLE_SIZE)
272 phase_R -= COS_TABLE_SIZE;
273
274 d_pos = delay * ptr->sample_rate / 1000.0f;
275 fpos_L = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_L]);
276 fpos_R = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_R]);
277
278 n_L = floorf(fpos_L);
279 n_R = floorf(fpos_R);
280 rem_L = fpos_L - n_L;
281 rem_R = fpos_R - n_R;
282
283 s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L,
284 ptr->pos_L, (unsigned long) n_L);
285 s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L,
286 ptr->pos_L, (unsigned long) n_L + 1);
287
288 s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R,
289 ptr->pos_R, (unsigned long) n_R);
290 s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R,
291 ptr->pos_R, (unsigned long) n_R + 1);
292
293 d_L = ((1 - rem_L) * s_a_L + rem_L * s_b_L);
294 d_R = ((1 - rem_R) * s_a_R + rem_R * s_b_R);
295
296 f_L = biquad_run(&ptr->highpass_L, d_L);
297 f_R = biquad_run(&ptr->highpass_R, d_R);
298
299 out_L = drylevel * in_L + wetlevel * f_L;
300 out_R = drylevel * in_R + wetlevel * f_R;
301
302 *(output_L++) = out_L;
303 *(output_R++) = out_R;
304 }
305 }
306
307
308 void
309 set_run_adding_gain_ChorusFlanger(LADSPA_Handle Instance, LADSPA_Data gain) {
310
311 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
312
313 ptr->run_adding_gain = gain;
314 }
315
316
317
318 void
319 run_adding_ChorusFlanger(LADSPA_Handle Instance,
320 unsigned long SampleCount) {
321
322 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
323
324 LADSPA_Data freq = LIMIT(*(ptr->freq), 0.0f, MAX_FREQ);
325 LADSPA_Data phase = LIMIT(*(ptr->phase), 0.0f, 180.0f) / 180.0f;
326 LADSPA_Data depth = 100.0f * ptr->sample_rate / 44100.0f
327 * LIMIT(*(ptr->depth),0.0f,100.0f) / 100.0f;
328 LADSPA_Data delay = LIMIT(*(ptr->delay),0.0f,100.0f);
329 LADSPA_Data contour = LIMIT(*(ptr->contour), 20.0f, 20000.0f);
330 LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
331 LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
332 LADSPA_Data * input_L = ptr->input_L;
333 LADSPA_Data * input_R = ptr->input_R;
334 LADSPA_Data * output_L = ptr->output_L;
335 LADSPA_Data * output_R = ptr->output_R;
336
337 unsigned long sample_index;
338 unsigned long sample_count = SampleCount;
339
340 LADSPA_Data in_L = 0.0f;
341 LADSPA_Data in_R = 0.0f;
342 LADSPA_Data d_L = 0.0f;
343 LADSPA_Data d_R = 0.0f;
344 LADSPA_Data f_L = 0.0f;
345 LADSPA_Data f_R = 0.0f;
346 LADSPA_Data out_L = 0.0f;
347 LADSPA_Data out_R = 0.0f;
348
349 float phase_L = 0.0f;
350 float phase_R = 0.0f;
351 float fpos_L = 0.0f;
352 float fpos_R = 0.0f;
353 float n_L = 0.0f;
354 float n_R = 0.0f;
355 float rem_L = 0.0f;
356 float rem_R = 0.0f;
357 float s_a_L, s_a_R, s_b_L, s_b_R;
358
359 float d_pos = 0.0f;
360
361 if (delay < 1.0f)
362 delay = 1.0f;
363 delay = 100.0f - delay;
364
365 hp_set_params(&ptr->highpass_L, contour, HP_BW, ptr->sample_rate);
366 hp_set_params(&ptr->highpass_R, contour, HP_BW, ptr->sample_rate);
367
368 for (sample_index = 0; sample_index < sample_count; sample_index++) {
369
370 in_L = *(input_L++);
371 in_R = *(input_R++);
372
373 push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L));
374 push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R));
375
376 ptr->cm_phase += freq / ptr->sample_rate * COS_TABLE_SIZE;
377
378 while (ptr->cm_phase >= COS_TABLE_SIZE)
379 ptr->cm_phase -= COS_TABLE_SIZE;
380
381 ptr->dm_phase = phase * COS_TABLE_SIZE / 2.0f;
382
383 phase_L = ptr->cm_phase;
384 phase_R = ptr->cm_phase + ptr->dm_phase;
385 while (phase_R >= COS_TABLE_SIZE)
386 phase_R -= COS_TABLE_SIZE;
387
388 d_pos = delay * ptr->sample_rate / 1000.0f;
389 fpos_L = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_L]);
390 fpos_R = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_R]);
391
392 n_L = floorf(fpos_L);
393 n_R = floorf(fpos_R);
394 rem_L = fpos_L - n_L;
395 rem_R = fpos_R - n_R;
396
397 s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L,
398 ptr->pos_L, (unsigned long) n_L);
399 s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L,
400 ptr->pos_L, (unsigned long) n_L + 1);
401
402 s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R,
403 ptr->pos_R, (unsigned long) n_R);
404 s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R,
405 ptr->pos_R, (unsigned long) n_R + 1);
406
407 d_L = ((1 - rem_L) * s_a_L + rem_L * s_b_L);
408 d_R = ((1 - rem_R) * s_a_R + rem_R * s_b_R);
409
410 f_L = biquad_run(&ptr->highpass_L, d_L);
411 f_R = biquad_run(&ptr->highpass_R, d_R);
412
413 out_L = drylevel * in_L + wetlevel * f_L;
414 out_R = drylevel * in_R + wetlevel * f_R;
415
416 *(output_L++) += ptr->run_adding_gain * out_L;
417 *(output_R++) += ptr->run_adding_gain * out_R;
418 }
419 }
420
421
422
423 /* Throw away a ChorusFlanger effect instance. */
424 void
425 cleanup_ChorusFlanger(LADSPA_Handle Instance) {
426
427 ChorusFlanger * ptr = (ChorusFlanger *)Instance;
428 free(ptr->ring_L);
429 free(ptr->ring_R);
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
442 _init() {
443
444 char ** port_names;
445 LADSPA_PortDescriptor * port_descriptors;
446 LADSPA_PortRangeHint * port_range_hints;
447 int i;
448
449 if ((stereo_descriptor =
450 (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
451 exit(1);
452
453 for (i = 0; i < COS_TABLE_SIZE; i++)
454 cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE);
455
456 stereo_descriptor->UniqueID = ID_STEREO;
457 stereo_descriptor->Label = strdup("tap_chorusflanger");
458 stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
459 stereo_descriptor->Name = strdup("TAP Chorus/Flanger");
460 stereo_descriptor->Maker = strdup("Tom Szilagyi");
461 stereo_descriptor->Copyright = strdup("GPL");
462 stereo_descriptor->PortCount = PORTCOUNT_STEREO;
463
464 if ((port_descriptors =
465 (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL)
466 exit(1);
467
468 stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
469 port_descriptors[FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
470 port_descriptors[PHASE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
471 port_descriptors[DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
472 port_descriptors[DELAY] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
473 port_descriptors[CONTOUR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
474 port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
475 port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
476 port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
477 port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
478 port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
479 port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
480
481 if ((port_names =
482 (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL)
483 exit(1);
484
485 stereo_descriptor->PortNames = (const char **)port_names;
486 port_names[FREQ] = strdup("Frequency [Hz]");
487 port_names[PHASE] = strdup("L/R Phase Shift [deg]");
488 port_names[DEPTH] = strdup("Depth [%]");
489 port_names[DELAY] = strdup("Delay [ms]");
490 port_names[CONTOUR] = strdup("Contour [Hz]");
491 port_names[DRYLEVEL] = strdup("Dry Level [dB]");
492 port_names[WETLEVEL] = strdup("Wet Level [dB]");
493 port_names[INPUT_L] = strdup("Input_L");
494 port_names[INPUT_R] = strdup("Input_R");
495 port_names[OUTPUT_L] = strdup("Output_L");
496 port_names[OUTPUT_R] = strdup("Output_R");
497
498 if ((port_range_hints =
499 ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL)
500 exit(1);
501
502 stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints;
503 port_range_hints[FREQ].HintDescriptor =
504 (LADSPA_HINT_BOUNDED_BELOW |
505 LADSPA_HINT_BOUNDED_ABOVE |
506 LADSPA_HINT_DEFAULT_LOW);
507 port_range_hints[PHASE].HintDescriptor =
508 (LADSPA_HINT_BOUNDED_BELOW |
509 LADSPA_HINT_BOUNDED_ABOVE |
510 LADSPA_HINT_DEFAULT_MIDDLE);
511 port_range_hints[DEPTH].HintDescriptor =
512 (LADSPA_HINT_BOUNDED_BELOW |
513 LADSPA_HINT_BOUNDED_ABOVE |
514 LADSPA_HINT_DEFAULT_HIGH);
515 port_range_hints[DELAY].HintDescriptor =
516 (LADSPA_HINT_BOUNDED_BELOW |
517 LADSPA_HINT_BOUNDED_ABOVE |
518 LADSPA_HINT_DEFAULT_LOW);
519 port_range_hints[CONTOUR].HintDescriptor =
520 (LADSPA_HINT_BOUNDED_BELOW |
521 LADSPA_HINT_BOUNDED_ABOVE |
522 LADSPA_HINT_DEFAULT_100);
523 port_range_hints[DRYLEVEL].HintDescriptor =
524 (LADSPA_HINT_BOUNDED_BELOW |
525 LADSPA_HINT_BOUNDED_ABOVE |
526 LADSPA_HINT_DEFAULT_0);
527 port_range_hints[WETLEVEL].HintDescriptor =
528 (LADSPA_HINT_BOUNDED_BELOW |
529 LADSPA_HINT_BOUNDED_ABOVE |
530 LADSPA_HINT_DEFAULT_0);
531 port_range_hints[FREQ].LowerBound = 0.0f;
532 port_range_hints[FREQ].UpperBound = MAX_FREQ;
533 port_range_hints[PHASE].LowerBound = 0.0f;
534 port_range_hints[PHASE].UpperBound = 180.0f;
535 port_range_hints[DEPTH].LowerBound = 0.0f;
536 port_range_hints[DEPTH].UpperBound = 100.0f;
537 port_range_hints[DELAY].LowerBound = 0.0f;
538 port_range_hints[DELAY].UpperBound = 100.0f;
539 port_range_hints[CONTOUR].LowerBound = 20.0f;
540 port_range_hints[CONTOUR].UpperBound = 20000.0f;
541 port_range_hints[DRYLEVEL].LowerBound = -90.0f;
542 port_range_hints[DRYLEVEL].UpperBound = +20.0f;
543 port_range_hints[WETLEVEL].LowerBound = -90.0f;
544 port_range_hints[WETLEVEL].UpperBound = +20.0f;
545 port_range_hints[INPUT_L].HintDescriptor = 0;
546 port_range_hints[INPUT_R].HintDescriptor = 0;
547 port_range_hints[OUTPUT_L].HintDescriptor = 0;
548 port_range_hints[OUTPUT_R].HintDescriptor = 0;
549 stereo_descriptor->instantiate = instantiate_ChorusFlanger;
550 stereo_descriptor->connect_port = connect_port_ChorusFlanger;
551 stereo_descriptor->activate = activate_ChorusFlanger;
552 stereo_descriptor->run = run_ChorusFlanger;
553 stereo_descriptor->run_adding = run_adding_ChorusFlanger;
554 stereo_descriptor->set_run_adding_gain = set_run_adding_gain_ChorusFlanger;
555 stereo_descriptor->deactivate = NULL;
556 stereo_descriptor->cleanup = cleanup_ChorusFlanger;
557 }
558
559
560 void
561 delete_descriptor(LADSPA_Descriptor * descriptor) {
562 unsigned long index;
563 if (descriptor) {
564 free((char *)descriptor->Label);
565 free((char *)descriptor->Name);
566 free((char *)descriptor->Maker);
567 free((char *)descriptor->Copyright);
568 free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
569 for (index = 0; index < descriptor->PortCount; index++)
570 free((char *)(descriptor->PortNames[index]));
571 free((char **)descriptor->PortNames);
572 free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
573 free(descriptor);
574 }
575 }
576
577
578 /* _fini() is called automatically when the library is unloaded. */
579 void
580 _fini() {
581 delete_descriptor(stereo_descriptor);
582 }
583
584
585 /* Return a descriptor of the requested plugin type. */
586 const LADSPA_Descriptor *
587 ladspa_descriptor(unsigned long Index) {
588
589 switch (Index) {
590 case 0:
591 return stereo_descriptor;
592 default:
593 return NULL;
594 }
595 }
596