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_reflector.c,v 1.1 2004/06/18 20:12: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 
31 /* The Unique ID of the plugin: */
32 
33 #define ID_MONO         2154
34 
35 /* The port numbers for the plugin: */
36 
37 #define FRAGMENT        0
38 #define DRYLEVEL        1
39 #define WETLEVEL        2
40 #define INPUT           3
41 #define OUTPUT          4
42 
43 /* Total number of ports */
44 
45 
46 #define PORTCOUNT_MONO   5
47 
48 
49 /* minimum & maximum fragment length [ms] */
50 #define MIN_FRAGMENT_LEN 20
51 #define MAX_FRAGMENT_LEN 1600
52 
53 /* in kHz */
54 #define MAX_SAMPLE_RATE 192
55 
56 
57 #define COS_TABLE_SIZE 1024
58 LADSPA_Data cos_table[COS_TABLE_SIZE];
59 
60 
61 
62 /* The structure used to hold port connection information and state */
63 
64 typedef struct {
65 	LADSPA_Data * fragment;
66 	LADSPA_Data * drylevel;
67 	LADSPA_Data * wetlevel;
68 	LADSPA_Data * input;
69 	LADSPA_Data * output;
70 
71 	LADSPA_Data * ring0;
72 	unsigned long buflen0;
73 	unsigned long pos0;
74 	LADSPA_Data * ring1;
75 	unsigned long buflen1;
76 	unsigned long pos1;
77 	LADSPA_Data * delay1;
78 	unsigned long delay_buflen1;
79 	unsigned long delay_pos1;
80 	LADSPA_Data * ring2;
81 	unsigned long buflen2;
82 	unsigned long pos2;
83 	LADSPA_Data * delay2;
84 	unsigned long delay_buflen2;
85 	unsigned long delay_pos2;
86 
87 	unsigned long fragment_pos;
88 
89 	unsigned long sample_rate;
90 	LADSPA_Data run_adding_gain;
91 } Reflector;
92 
93 
94 
95 /* Construct a new plugin instance. */
96 LADSPA_Handle
instantiate_Reflector(const LADSPA_Descriptor * Descriptor,unsigned long sample_rate)97 instantiate_Reflector(const LADSPA_Descriptor * Descriptor,
98 		      unsigned long             sample_rate) {
99 
100         LADSPA_Handle * ptr;
101 
102 	if ((ptr = malloc(sizeof(Reflector))) != NULL) {
103 		((Reflector *)ptr)->sample_rate = sample_rate;
104 		((Reflector *)ptr)->run_adding_gain = 1.0f;
105 
106 		if ((((Reflector *)ptr)->ring0 =
107 		     calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
108 			return NULL;
109 		((Reflector *)ptr)->buflen0 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
110 		((Reflector *)ptr)->pos0 = 0;
111 
112 		if ((((Reflector *)ptr)->ring1 =
113 		     calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
114 			return NULL;
115 		((Reflector *)ptr)->buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
116 		((Reflector *)ptr)->pos1 = 0;
117 
118 		if ((((Reflector *)ptr)->delay1 =
119 		     calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
120 			return NULL;
121 		((Reflector *)ptr)->delay_buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 3000;
122 		((Reflector *)ptr)->pos1 = 0;
123 
124 		if ((((Reflector *)ptr)->ring2 =
125 		     calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
126 			return NULL;
127 		((Reflector *)ptr)->buflen2 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
128 		((Reflector *)ptr)->pos2 = 0;
129 
130 		if ((((Reflector *)ptr)->delay2 =
131 		     calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
132 			return NULL;
133 		((Reflector *)ptr)->delay_buflen2 = 4 * MAX_FRAGMENT_LEN * sample_rate / 3000;
134 		((Reflector *)ptr)->pos2 = 0;
135 
136 		return ptr;
137 	}
138        	return NULL;
139 }
140 
141 
142 void
activate_Reflector(LADSPA_Handle Instance)143 activate_Reflector(LADSPA_Handle Instance) {
144 
145 	Reflector * ptr = (Reflector *)Instance;
146 	unsigned long i;
147 
148 	for (i = 0; i < ptr->buflen0; i++)
149 		ptr->ring0[i] = 0.0f;
150 	ptr->pos0 = 0;
151 	for (i = 0; i < ptr->buflen1; i++)
152 		ptr->ring1[i] = 0.0f;
153 	ptr->pos1 = 0;
154 	for (i = 0; i < ptr->buflen2; i++)
155 		ptr->ring2[i] = 0.0f;
156 	ptr->pos2 = 0;
157 
158 	for (i = 0; i < ptr->delay_buflen1; i++)
159 		ptr->delay1[i] = 0.0f;
160 	ptr->delay_pos1 = 0;
161 	for (i = 0; i < ptr->delay_buflen2; i++)
162 		ptr->delay2[i] = 0.0f;
163 	ptr->delay_pos2 = 0;
164 
165 	ptr->fragment_pos = 0;
166 }
167 
168 
169 
170 
171 
172 /* Connect a port to a data location. */
173 void
connect_port_Reflector(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)174 connect_port_Reflector(LADSPA_Handle Instance,
175 		       unsigned long Port,
176 		       LADSPA_Data * DataLocation) {
177 
178 	Reflector * ptr = (Reflector *)Instance;
179 
180 	switch (Port) {
181 	case FRAGMENT:
182 		ptr->fragment = DataLocation;
183 		break;
184 	case DRYLEVEL:
185 		ptr->drylevel = DataLocation;
186 		break;
187 	case WETLEVEL:
188 		ptr->wetlevel = DataLocation;
189 		break;
190 	case INPUT:
191 		ptr->input = DataLocation;
192 		break;
193 	case OUTPUT:
194 		ptr->output = DataLocation;
195 		break;
196 	}
197 }
198 
199 
200 
201 void
run_Reflector(LADSPA_Handle Instance,unsigned long SampleCount)202 run_Reflector(LADSPA_Handle Instance,
203 	      unsigned long SampleCount) {
204 
205 	Reflector * ptr = (Reflector *)Instance;
206 	LADSPA_Data * input = ptr->input;
207 	LADSPA_Data * output = ptr->output;
208 	LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
209 	LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
210 	LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN);
211 
212 	unsigned long sample_index;
213 	unsigned long sample_count = SampleCount;
214 
215 	LADSPA_Data in = 0.0f;
216 	LADSPA_Data in1 = 0.0f;
217 	LADSPA_Data in2 = 0.0f;
218 	LADSPA_Data out_0 = 0.0f;
219 	LADSPA_Data out_1 = 0.0f;
220 	LADSPA_Data out_2 = 0.0f;
221 
222 	unsigned long fragment_pos1 = 0;
223 	unsigned long fragment_pos2 = 0;
224 
225 	unsigned long arg_0 = 0;
226 	LADSPA_Data am_0 = 0.0f;
227 	unsigned long arg_1 = 0;
228 	LADSPA_Data am_1 = 0.0f;
229 	unsigned long arg_2 = 0;
230 	LADSPA_Data am_2 = 0.0f;
231 
232 	ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f;
233 	ptr->buflen1 = ptr->buflen0;
234 	ptr->buflen2 = ptr->buflen0;
235 	ptr->delay_buflen1 = ptr->buflen0 / 3;
236 	ptr->delay_buflen2 = 2 * ptr->buflen0 / 3;
237 
238 	for (sample_index = 0; sample_index < sample_count; sample_index++) {
239 
240 		in = *(input++);
241 		in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1));
242 		in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2));
243 
244 		push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0));
245 		push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1));
246 		push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2));
247 
248 		fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0;
249 		fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1;
250 
251 		out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0,
252 				    ptr->buflen0 - ptr->fragment_pos - 1);
253 		out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1,
254 				    ptr->buflen1 - fragment_pos1 - 1);
255 		out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2,
256 				    ptr->buflen2 - fragment_pos2 - 1);
257 
258 		ptr->fragment_pos += 2;
259 		if (ptr->fragment_pos >= ptr->buflen0)
260 			ptr->fragment_pos = 0;
261 
262 		arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE;
263 		am_0 = 1.0f - cos_table[arg_0];
264 		arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE;
265 		am_1 = 1.0f - cos_table[arg_1];
266 		arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE;
267 		am_2 = 1.0f - cos_table[arg_2];
268 
269 		*(output++) = drylevel * in + wetlevel *
270 			(am_0 * out_0 + am_1 * out_1 + am_2 * out_2);
271 	}
272 }
273 
274 
275 
276 void
set_run_adding_gain_Reflector(LADSPA_Handle Instance,LADSPA_Data gain)277 set_run_adding_gain_Reflector(LADSPA_Handle Instance, LADSPA_Data gain) {
278 
279 	Reflector * ptr = (Reflector *)Instance;
280 
281 	ptr->run_adding_gain = gain;
282 }
283 
284 
285 
286 void
run_adding_Reflector(LADSPA_Handle Instance,unsigned long SampleCount)287 run_adding_Reflector(LADSPA_Handle Instance,
288 		     unsigned long SampleCount) {
289 
290 	Reflector * ptr = (Reflector *)Instance;
291 	LADSPA_Data * input = ptr->input;
292 	LADSPA_Data * output = ptr->output;
293 	LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
294 	LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
295 	LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN);
296 
297 	unsigned long sample_index;
298 	unsigned long sample_count = SampleCount;
299 
300 	LADSPA_Data in = 0.0f;
301 	LADSPA_Data in1 = 0.0f;
302 	LADSPA_Data in2 = 0.0f;
303 	LADSPA_Data out_0 = 0.0f;
304 	LADSPA_Data out_1 = 0.0f;
305 	LADSPA_Data out_2 = 0.0f;
306 
307 	unsigned long fragment_pos1 = 0;
308 	unsigned long fragment_pos2 = 0;
309 
310 	unsigned long arg_0 = 0;
311 	LADSPA_Data am_0 = 0.0f;
312 	unsigned long arg_1 = 0;
313 	LADSPA_Data am_1 = 0.0f;
314 	unsigned long arg_2 = 0;
315 	LADSPA_Data am_2 = 0.0f;
316 
317 	ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f;
318 	ptr->buflen1 = ptr->buflen0;
319 	ptr->buflen2 = ptr->buflen0;
320 	ptr->delay_buflen1 = ptr->buflen0 / 3;
321 	ptr->delay_buflen2 = 2 * ptr->buflen0 / 3;
322 
323 	for (sample_index = 0; sample_index < sample_count; sample_index++) {
324 
325 		in = *(input++);
326 		in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1));
327 		in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2));
328 
329 		push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0));
330 		push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1));
331 		push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2));
332 
333 		fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0;
334 		fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1;
335 
336 		out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0,
337 				    ptr->buflen0 - ptr->fragment_pos - 1);
338 		out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1,
339 				    ptr->buflen1 - fragment_pos1 - 1);
340 		out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2,
341 				    ptr->buflen2 - fragment_pos2 - 1);
342 
343 		ptr->fragment_pos += 2;
344 		if (ptr->fragment_pos >= ptr->buflen0)
345 			ptr->fragment_pos = 0;
346 
347 		arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE;
348 		am_0 = 1.0f - cos_table[arg_0];
349 		arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE;
350 		am_1 = 1.0f - cos_table[arg_1];
351 		arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE;
352 		am_2 = 1.0f - cos_table[arg_2];
353 
354 		*(output++) += ptr->run_adding_gain *
355 			(drylevel * in + wetlevel * (am_0 * out_0 + am_1 * out_1 + am_2 * out_2));
356 	}
357 }
358 
359 
360 
361 
362 /* Throw away a Reflector effect instance. */
363 void
cleanup_Reflector(LADSPA_Handle Instance)364 cleanup_Reflector(LADSPA_Handle Instance) {
365 
366   	Reflector * ptr = (Reflector *)Instance;
367 	free(ptr->ring0);
368 	free(ptr->ring1);
369 	free(ptr->ring2);
370 	free(ptr->delay1);
371 	free(ptr->delay2);
372 	free(Instance);
373 }
374 
375 
376 
377 LADSPA_Descriptor * mono_descriptor = NULL;
378 
379 
380 
381 /* _init() is called automatically when the plugin library is first
382    loaded. */
383 void
_init()384 _init() {
385 
386 	int i;
387 	char ** port_names;
388 	LADSPA_PortDescriptor * port_descriptors;
389 	LADSPA_PortRangeHint * port_range_hints;
390 
391 	if ((mono_descriptor =
392 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
393 		exit(1);
394 
395 	for (i = 0; i < COS_TABLE_SIZE; i++)
396 		cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE);
397 
398 
399 	mono_descriptor->UniqueID = ID_MONO;
400 	mono_descriptor->Label = strdup("tap_reflector");
401 	mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
402 	mono_descriptor->Name = strdup("TAP Reflector");
403 	mono_descriptor->Maker = strdup("Tom Szilagyi");
404 	mono_descriptor->Copyright = strdup("GPL");
405 	mono_descriptor->PortCount = PORTCOUNT_MONO;
406 
407 	if ((port_descriptors =
408 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
409 		exit(1);
410 
411 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
412 	port_descriptors[FRAGMENT] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
413 	port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
414 	port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
415 	port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
416 	port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
417 
418 	if ((port_names =
419 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
420 		exit(1);
421 
422 	mono_descriptor->PortNames = (const char **)port_names;
423 	port_names[FRAGMENT] = strdup("Fragment Length [ms]");
424 	port_names[DRYLEVEL] = strdup("Dry Level [dB]");
425 	port_names[WETLEVEL] = strdup("Wet Level [dB]");
426 	port_names[INPUT] = strdup("Input");
427 	port_names[OUTPUT] = strdup("Output");
428 
429 	if ((port_range_hints =
430 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
431 		exit(1);
432 
433 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
434 	port_range_hints[FRAGMENT].HintDescriptor =
435 		(LADSPA_HINT_BOUNDED_BELOW |
436 		 LADSPA_HINT_BOUNDED_ABOVE |
437 		 LADSPA_HINT_DEFAULT_LOW);
438 	port_range_hints[DRYLEVEL].HintDescriptor =
439 		(LADSPA_HINT_BOUNDED_BELOW |
440 		 LADSPA_HINT_BOUNDED_ABOVE |
441 		 LADSPA_HINT_DEFAULT_MINIMUM);
442 	port_range_hints[WETLEVEL].HintDescriptor =
443 		(LADSPA_HINT_BOUNDED_BELOW |
444 		 LADSPA_HINT_BOUNDED_ABOVE |
445 		 LADSPA_HINT_DEFAULT_0);
446 	port_range_hints[FRAGMENT].LowerBound = (float)MIN_FRAGMENT_LEN;
447 	port_range_hints[FRAGMENT].UpperBound = (float)MAX_FRAGMENT_LEN;
448 	port_range_hints[DRYLEVEL].LowerBound = -90.0f;
449 	port_range_hints[DRYLEVEL].UpperBound = 20.0f;
450 	port_range_hints[WETLEVEL].LowerBound = -90.0f;
451 	port_range_hints[WETLEVEL].UpperBound = 20.0f;
452 	port_range_hints[INPUT].HintDescriptor = 0;
453 	port_range_hints[OUTPUT].HintDescriptor = 0;
454 	mono_descriptor->instantiate = instantiate_Reflector;
455 	mono_descriptor->connect_port = connect_port_Reflector;
456 	mono_descriptor->activate = activate_Reflector;
457 	mono_descriptor->run = run_Reflector;
458 	mono_descriptor->run_adding = run_adding_Reflector;
459 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_Reflector;
460 	mono_descriptor->deactivate = NULL;
461 	mono_descriptor->cleanup = cleanup_Reflector;
462 }
463 
464 
465 void
delete_descriptor(LADSPA_Descriptor * descriptor)466 delete_descriptor(LADSPA_Descriptor * descriptor) {
467 	unsigned long index;
468 	if (descriptor) {
469 		free((char *)descriptor->Label);
470 		free((char *)descriptor->Name);
471 		free((char *)descriptor->Maker);
472 		free((char *)descriptor->Copyright);
473 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
474 		for (index = 0; index < descriptor->PortCount; index++)
475 			free((char *)(descriptor->PortNames[index]));
476 		free((char **)descriptor->PortNames);
477 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
478 		free(descriptor);
479 	}
480 }
481 
482 
483 /* _fini() is called automatically when the library is unloaded. */
484 void
_fini()485 _fini() {
486 	delete_descriptor(mono_descriptor);
487 }
488 
489 
490 /* Return a descriptor of the requested plugin type. */
491 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)492 ladspa_descriptor(unsigned long Index) {
493 
494 	switch (Index) {
495 	case 0:
496 		return mono_descriptor;
497 	default:
498 		return NULL;
499 	}
500 }
501