1 /*                                                     -*- linux-c -*-
2     Copyright (C) 2004 Tom Szilagyi
3 
4     Patches were received from:
5         Alexander Koenig <alex@lisas.de>
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21     $Id: tap_autopan.c,v 1.6 2004/02/21 17:33:36 tszilagyi Exp $
22 */
23 
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29 
30 #include "ladspa.h"
31 #include "tap_utils.h"
32 
33 /* The Unique ID of the plugin: */
34 
35 #define ID_STEREO         2146
36 
37 /* The port numbers for the plugin: */
38 
39 #define CONTROL_FREQ    0
40 #define CONTROL_DEPTH   1
41 #define CONTROL_GAIN    2
42 #define INPUT_L         3
43 #define INPUT_R         4
44 #define OUTPUT_L        5
45 #define OUTPUT_R        6
46 
47 
48 /* Total number of ports */
49 
50 #define PORTCOUNT_STEREO   7
51 
52 
53 /* cosine table for fast computations */
54 LADSPA_Data cos_table[1024];
55 
56 
57 /* The structure used to hold port connection information and state */
58 
59 typedef struct {
60 	LADSPA_Data * freq;
61 	LADSPA_Data * depth;
62 	LADSPA_Data * gain;
63 	LADSPA_Data * input_L;
64 	LADSPA_Data * input_R;
65 	LADSPA_Data * output_L;
66 	LADSPA_Data * output_R;
67 	unsigned long SampleRate;
68 	LADSPA_Data Phase;
69 	LADSPA_Data run_adding_gain;
70 } AutoPan;
71 
72 
73 
74 /* Construct a new plugin instance. */
75 LADSPA_Handle
instantiate_AutoPan(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)76 instantiate_AutoPan(const LADSPA_Descriptor * Descriptor,
77 		    unsigned long             SampleRate) {
78 
79 	LADSPA_Handle * ptr;
80 
81 	if ((ptr = malloc(sizeof(AutoPan))) != NULL) {
82 		((AutoPan *)ptr)->SampleRate = SampleRate;
83 		((AutoPan *)ptr)->run_adding_gain = 1.0;
84 		return ptr;
85 	}
86 
87 	return NULL;
88 }
89 
90 void
activate_AutoPan(LADSPA_Handle Instance)91 activate_AutoPan(LADSPA_Handle Instance) {
92 
93 	AutoPan * ptr;
94 
95 	ptr = (AutoPan *)Instance;
96 	ptr->Phase = 0.0f;
97 }
98 
99 
100 
101 /* Connect a port to a data location. */
102 void
connect_port_AutoPan(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)103 connect_port_AutoPan(LADSPA_Handle Instance,
104 		     unsigned long Port,
105 		     LADSPA_Data * DataLocation) {
106 
107 	AutoPan * ptr;
108 
109 	ptr = (AutoPan *)Instance;
110 	switch (Port) {
111 	case CONTROL_FREQ:
112 		ptr->freq = DataLocation;
113 		break;
114 	case CONTROL_DEPTH:
115 		ptr->depth = DataLocation;
116 		break;
117 	case CONTROL_GAIN:
118 		ptr->gain = DataLocation;
119 		break;
120 	case INPUT_L:
121 		ptr->input_L = DataLocation;
122 		break;
123 	case INPUT_R:
124 		ptr->input_R = DataLocation;
125 		break;
126 	case OUTPUT_L:
127 		ptr->output_L = DataLocation;
128 		break;
129 	case OUTPUT_R:
130 		ptr->output_R = DataLocation;
131 		break;
132 	}
133 }
134 
135 
136 
137 void
run_AutoPan(LADSPA_Handle Instance,unsigned long SampleCount)138 run_AutoPan(LADSPA_Handle Instance,
139 	    unsigned long SampleCount) {
140 
141 	AutoPan * ptr = (AutoPan *)Instance;
142 
143 	LADSPA_Data * input_L = ptr->input_L;
144 	LADSPA_Data * input_R = ptr->input_R;
145 	LADSPA_Data * output_L = ptr->output_L;
146 	LADSPA_Data * output_R = ptr->output_R;
147 	LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,20.0f);
148 	LADSPA_Data depth = LIMIT(*(ptr->depth),0.0f,100.0f);
149 	LADSPA_Data gain = db2lin(LIMIT(*(ptr->gain),-70.0f,20.0f));
150 	unsigned long sample_index;
151 	LADSPA_Data phase_L = 0;
152 	LADSPA_Data phase_R = 0;
153 
154 	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
155 		phase_L = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase;
156 		while (phase_L >= 1024.0f)
157 		        phase_L -= 1024.0f;
158  		phase_R = phase_L + 512.0f;
159 		while (phase_R >= 1024.0f)
160 		        phase_R -= 1024.0f;
161 
162 		*(output_L++) = *(input_L++) * gain *
163 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_L]);
164 		*(output_R++) = *(input_R++) * gain *
165 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_R]);
166 	}
167 	ptr->Phase = phase_L;
168 	while (ptr->Phase >= 1024.0f)
169 		ptr->Phase -= 1024.0f;
170 }
171 
172 
173 
174 void
set_run_adding_gain_AutoPan(LADSPA_Handle Instance,LADSPA_Data gain)175 set_run_adding_gain_AutoPan(LADSPA_Handle Instance, LADSPA_Data gain) {
176 
177 	AutoPan * ptr;
178 
179 	ptr = (AutoPan *)Instance;
180 
181 	ptr->run_adding_gain = gain;
182 }
183 
184 
185 
186 void
run_adding_AutoPan(LADSPA_Handle Instance,unsigned long SampleCount)187 run_adding_AutoPan(LADSPA_Handle Instance,
188 		   unsigned long SampleCount) {
189 
190 	AutoPan * ptr = (AutoPan *)Instance;
191 
192 	LADSPA_Data * input_L = ptr->input_L;
193 	LADSPA_Data * input_R = ptr->input_R;
194 	LADSPA_Data * output_L = ptr->output_L;
195 	LADSPA_Data * output_R = ptr->output_R;
196 	LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,20.0f);
197 	LADSPA_Data depth = LIMIT(*(ptr->depth),0.0f,100.0f);
198 	LADSPA_Data gain = db2lin(LIMIT(*(ptr->gain),-70.0f,20.0f));
199 	unsigned long sample_index;
200 	LADSPA_Data phase_L = 0;
201 	LADSPA_Data phase_R = 0;
202 
203 	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
204 		phase_L = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase;
205 		while (phase_L >= 1024.0f)
206 		        phase_L -= 1024.0f;
207  		phase_R = phase_L + 512.0f;
208 		while (phase_R >= 1024.0f)
209 		        phase_R -= 1024.0f;
210 
211 		*(output_L++) += *(input_L++) * gain * ptr->run_adding_gain *
212 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_L]);
213 		*(output_R++) += *(input_R++) * gain * ptr->run_adding_gain *
214 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_R]);
215 	}
216 	ptr->Phase = phase_L;
217 	while (ptr->Phase >= 1024.0f)
218 		ptr->Phase -= 1024.0f;
219 }
220 
221 
222 
223 
224 /* Throw away an AutoPan effect instance. */
225 void
cleanup_AutoPan(LADSPA_Handle Instance)226 cleanup_AutoPan(LADSPA_Handle Instance) {
227 	free(Instance);
228 }
229 
230 
231 
232 LADSPA_Descriptor * mono_descriptor = NULL;
233 
234 
235 
236 /* _init() is called automatically when the plugin library is first
237    loaded. */
238 void
_init()239 _init() {
240 
241 	int i;
242 	char ** port_names;
243 	LADSPA_PortDescriptor * port_descriptors;
244 	LADSPA_PortRangeHint * port_range_hints;
245 
246 	if ((mono_descriptor =
247 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
248 		exit(1);
249 
250 	for (i = 0; i < 1024; i++)
251 		cos_table[i] = cosf(i * M_PI / 512.0f);
252 
253 
254 	mono_descriptor->UniqueID = ID_STEREO;
255 	mono_descriptor->Label = strdup("tap_autopan");
256 	mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
257 	mono_descriptor->Name = strdup("TAP AutoPanner");
258 	mono_descriptor->Maker = strdup("Tom Szilagyi");
259 	mono_descriptor->Copyright = strdup("GPL");
260 	mono_descriptor->PortCount = PORTCOUNT_STEREO;
261 
262 	if ((port_descriptors =
263 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL)
264 		exit(1);
265 
266 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
267 	port_descriptors[CONTROL_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
268 	port_descriptors[CONTROL_DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
269 	port_descriptors[CONTROL_GAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
270 	port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
271 	port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
272 	port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
273 	port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
274 
275 	if ((port_names =
276 	     (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL)
277 		exit(1);
278 
279 	mono_descriptor->PortNames = (const char **)port_names;
280 	port_names[CONTROL_FREQ] = strdup("Frequency [Hz]");
281 	port_names[CONTROL_DEPTH] = strdup("Depth [%]");
282 	port_names[CONTROL_GAIN] = strdup("Gain [dB]");
283 	port_names[INPUT_L] = strdup("Input L");
284 	port_names[INPUT_R] = strdup("Input R");
285 	port_names[OUTPUT_L] = strdup("Output L");
286 	port_names[OUTPUT_R] = strdup("Output R");
287 
288 	if ((port_range_hints =
289 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL)
290 		exit(1);
291 
292 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
293 	port_range_hints[CONTROL_FREQ].HintDescriptor =
294 		(LADSPA_HINT_BOUNDED_BELOW |
295 		 LADSPA_HINT_BOUNDED_ABOVE |
296 		 LADSPA_HINT_DEFAULT_0);
297 	port_range_hints[CONTROL_DEPTH].HintDescriptor =
298 		(LADSPA_HINT_BOUNDED_BELOW |
299 		 LADSPA_HINT_BOUNDED_ABOVE |
300 		 LADSPA_HINT_DEFAULT_0);
301 	port_range_hints[CONTROL_GAIN].HintDescriptor =
302 		(LADSPA_HINT_BOUNDED_BELOW |
303 		 LADSPA_HINT_BOUNDED_ABOVE |
304 		 LADSPA_HINT_DEFAULT_0);
305 	port_range_hints[CONTROL_FREQ].LowerBound = 0;
306 	port_range_hints[CONTROL_FREQ].UpperBound = 20;
307 	port_range_hints[CONTROL_DEPTH].LowerBound = 0;
308 	port_range_hints[CONTROL_DEPTH].UpperBound = 100;
309 	port_range_hints[CONTROL_GAIN].LowerBound = -70;
310 	port_range_hints[CONTROL_GAIN].UpperBound = 20;
311 	port_range_hints[INPUT_L].HintDescriptor = 0;
312 	port_range_hints[INPUT_R].HintDescriptor = 0;
313 	port_range_hints[OUTPUT_L].HintDescriptor = 0;
314 	port_range_hints[OUTPUT_R].HintDescriptor = 0;
315 	mono_descriptor->instantiate = instantiate_AutoPan;
316 	mono_descriptor->connect_port = connect_port_AutoPan;
317 	mono_descriptor->activate = activate_AutoPan;
318 	mono_descriptor->run = run_AutoPan;
319 	mono_descriptor->run_adding = run_adding_AutoPan;
320 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_AutoPan;
321 	mono_descriptor->deactivate = NULL;
322 	mono_descriptor->cleanup = cleanup_AutoPan;
323 }
324 
325 
326 void
delete_descriptor(LADSPA_Descriptor * descriptor)327 delete_descriptor(LADSPA_Descriptor * descriptor) {
328 	unsigned long index;
329 	if (descriptor) {
330 		free((char *)descriptor->Label);
331 		free((char *)descriptor->Name);
332 		free((char *)descriptor->Maker);
333 		free((char *)descriptor->Copyright);
334 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
335 		for (index = 0; index < descriptor->PortCount; index++)
336 			free((char *)(descriptor->PortNames[index]));
337 		free((char **)descriptor->PortNames);
338 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
339 		free(descriptor);
340 	}
341 }
342 
343 
344 /* _fini() is called automatically when the library is unloaded. */
345 void
_fini()346 _fini() {
347 	delete_descriptor(mono_descriptor);
348 }
349 
350 
351 /* Return a descriptor of the requested plugin type. */
352 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)353 ladspa_descriptor(unsigned long Index) {
354 
355 	switch (Index) {
356 	case 0:
357 		return mono_descriptor;
358 	default:
359 		return NULL;
360 	}
361 }
362