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