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