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_tremolo.c,v 1.6 2004/02/21 17:33:36 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 /* The Unique ID of the plugin: */
31 
32 #define ID_MONO         2144
33 
34 /* The port numbers for the plugin: */
35 
36 #define CONTROL_FREQ    0
37 #define CONTROL_DEPTH   1
38 #define CONTROL_GAIN    2
39 #define INPUT_0         3
40 #define OUTPUT_0        4
41 
42 
43 /* Total number of ports */
44 
45 #define PORTCOUNT_MONO   5
46 
47 
48 /* cosine table for fast computations */
49 LADSPA_Data cos_table[1024];
50 
51 
52 /* The structure used to hold port connection information and state */
53 
54 typedef struct {
55 	LADSPA_Data * Control_Freq;
56 	LADSPA_Data * Control_Depth;
57 	LADSPA_Data * Control_Gain;
58 	LADSPA_Data * InputBuffer_1;
59 	LADSPA_Data * OutputBuffer_1;
60 	unsigned long SampleRate;
61 	LADSPA_Data Phase;
62 	LADSPA_Data run_adding_gain;
63 } Tremolo;
64 
65 
66 
67 /* Construct a new plugin instance. */
68 LADSPA_Handle
instantiate_Tremolo(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)69 instantiate_Tremolo(const LADSPA_Descriptor * Descriptor,
70 		    unsigned long             SampleRate) {
71 
72 	LADSPA_Handle * ptr;
73 
74 	if ((ptr = malloc(sizeof(Tremolo))) != NULL) {
75 	        ((Tremolo *)ptr)->SampleRate = SampleRate;
76 	        ((Tremolo *)ptr)->run_adding_gain = 1.0;
77 		return ptr;
78 	}
79 
80 	return NULL;
81 }
82 
83 void
activate_Tremolo(LADSPA_Handle Instance)84 activate_Tremolo(LADSPA_Handle Instance) {
85 
86 	Tremolo * ptr;
87 
88 	ptr = (Tremolo *)Instance;
89 	ptr->Phase = 0.0f;
90 }
91 
92 
93 
94 /* Connect a port to a data location. */
95 void
connect_port_Tremolo(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)96 connect_port_Tremolo(LADSPA_Handle Instance,
97 		     unsigned long Port,
98 		     LADSPA_Data * DataLocation) {
99 
100 	Tremolo * ptr;
101 
102 	ptr = (Tremolo *)Instance;
103 	switch (Port) {
104 	case CONTROL_FREQ:
105 		ptr->Control_Freq = DataLocation;
106 		break;
107 	case CONTROL_DEPTH:
108 		ptr->Control_Depth = DataLocation;
109 		break;
110 	case CONTROL_GAIN:
111 		ptr->Control_Gain = DataLocation;
112 		break;
113 	case INPUT_0:
114 		ptr->InputBuffer_1 = DataLocation;
115 		break;
116 	case OUTPUT_0:
117 		ptr->OutputBuffer_1 = DataLocation;
118 		break;
119 	}
120 }
121 
122 
123 
124 void
run_Tremolo(LADSPA_Handle Instance,unsigned long SampleCount)125 run_Tremolo(LADSPA_Handle Instance,
126 	    unsigned long SampleCount) {
127 
128 	LADSPA_Data * input;
129 	LADSPA_Data * output;
130 	LADSPA_Data freq;
131 	LADSPA_Data depth;
132 	LADSPA_Data gain;
133 	Tremolo * ptr;
134 	unsigned long sample_index;
135 	LADSPA_Data phase = 0.0f;
136 
137 	ptr = (Tremolo *)Instance;
138 
139 	input = ptr->InputBuffer_1;
140 	output = ptr->OutputBuffer_1;
141 	freq = LIMIT(*(ptr->Control_Freq),0.0f,20.0f);
142 	depth = LIMIT(*(ptr->Control_Depth),0.0f,100.0f);
143 	gain = db2lin(LIMIT(*(ptr->Control_Gain),-70.0f,20.0f));
144 
145   	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
146 		phase = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase;
147 
148 		while (phase >= 1024.0f)
149 			phase -= 1024.0f;
150 
151 		*(output++) = *(input++) * gain *
152 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase]);
153 	}
154 	ptr->Phase = phase;
155 	while (ptr->Phase >= 1024.0f)
156 		ptr->Phase -= 1024.0f;
157 }
158 
159 
160 
161 void
set_run_adding_gain_Tremolo(LADSPA_Handle Instance,LADSPA_Data gain)162 set_run_adding_gain_Tremolo(LADSPA_Handle Instance, LADSPA_Data gain) {
163 
164 	Tremolo * ptr;
165 
166 	ptr = (Tremolo *)Instance;
167 
168 	ptr->run_adding_gain = gain;
169 }
170 
171 
172 
173 void
run_adding_Tremolo(LADSPA_Handle Instance,unsigned long SampleCount)174 run_adding_Tremolo(LADSPA_Handle Instance,
175 		   unsigned long SampleCount) {
176 
177 	LADSPA_Data * input;
178 	LADSPA_Data * output;
179 	LADSPA_Data freq;
180 	LADSPA_Data depth;
181 	LADSPA_Data gain;
182 	Tremolo * ptr;
183 	unsigned long sample_index;
184 	LADSPA_Data phase = 0.0f;
185 
186 	ptr = (Tremolo *)Instance;
187 
188 	input = ptr->InputBuffer_1;
189 	output = ptr->OutputBuffer_1;
190 	freq = LIMIT(*(ptr->Control_Freq),0.0f,20.0f);
191 	depth = LIMIT(*(ptr->Control_Depth),0.0f,100.0f);
192 	gain = db2lin(LIMIT(*(ptr->Control_Gain),-70.0f,20.0f));
193 
194   	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
195 		phase = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase;
196 
197 		while (phase >= 1024.0f)
198 			phase -= 1024.0f;
199 
200 		*(output++) += *(input++) * ptr->run_adding_gain * gain *
201 			(1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase]);
202 	}
203 	ptr->Phase = phase;
204 	while (ptr->Phase >= 1024.0f)
205 		ptr->Phase -= 1024.0f;
206 }
207 
208 
209 
210 
211 /* Throw away a Tremolo effect instance. */
212 void
cleanup_Tremolo(LADSPA_Handle Instance)213 cleanup_Tremolo(LADSPA_Handle Instance) {
214 	free(Instance);
215 }
216 
217 
218 
219 LADSPA_Descriptor * mono_descriptor = NULL;
220 
221 
222 
223 /* _init() is called automatically when the plugin library is first
224    loaded. */
225 void
_init()226 _init() {
227 
228 	char ** port_names;
229 	LADSPA_PortDescriptor * port_descriptors;
230 	LADSPA_PortRangeHint * port_range_hints;
231 	int i;
232 
233 	if ((mono_descriptor =
234 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
235 		exit(1);
236 
237 
238 	for (i = 0; i < 1024; i++)
239 		cos_table[i] = cosf(i * M_PI / 512.0f);
240 
241 
242 	mono_descriptor->UniqueID = ID_MONO;
243 	mono_descriptor->Label = strdup("tap_tremolo");
244 	mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
245 	mono_descriptor->Name = strdup("TAP Tremolo");
246 	mono_descriptor->Maker = strdup("Tom Szilagyi");
247 	mono_descriptor->Copyright = strdup("GPL");
248 	mono_descriptor->PortCount = PORTCOUNT_MONO;
249 
250 	if ((port_descriptors =
251 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
252 		exit(1);
253 
254 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
255 	port_descriptors[CONTROL_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
256 	port_descriptors[CONTROL_DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
257 	port_descriptors[CONTROL_GAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
258 	port_descriptors[INPUT_0] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
259 	port_descriptors[OUTPUT_0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
260 
261 	if ((port_names =
262 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
263 		exit(1);
264 
265 	mono_descriptor->PortNames = (const char **)port_names;
266 	port_names[CONTROL_FREQ] = strdup("Frequency [Hz]");
267 	port_names[CONTROL_DEPTH] = strdup("Depth [%]");
268 	port_names[CONTROL_GAIN] = strdup("Gain [dB]");
269 	port_names[INPUT_0] = strdup("Input_0");
270 	port_names[OUTPUT_0] = strdup("Output_0");
271 
272 	if ((port_range_hints =
273 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
274 		exit(1);
275 
276 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
277 	port_range_hints[CONTROL_FREQ].HintDescriptor =
278 		(LADSPA_HINT_BOUNDED_BELOW |
279 		 LADSPA_HINT_BOUNDED_ABOVE |
280 		 LADSPA_HINT_DEFAULT_0);
281 	port_range_hints[CONTROL_DEPTH].HintDescriptor =
282 		(LADSPA_HINT_BOUNDED_BELOW |
283 		 LADSPA_HINT_BOUNDED_ABOVE |
284 		 LADSPA_HINT_DEFAULT_0);
285 	port_range_hints[CONTROL_GAIN].HintDescriptor =
286 		(LADSPA_HINT_BOUNDED_BELOW |
287 		 LADSPA_HINT_BOUNDED_ABOVE |
288 		 LADSPA_HINT_DEFAULT_0);
289 	port_range_hints[CONTROL_FREQ].LowerBound = 0;
290 	port_range_hints[CONTROL_FREQ].UpperBound = 20;
291 	port_range_hints[CONTROL_DEPTH].LowerBound = 0;
292 	port_range_hints[CONTROL_DEPTH].UpperBound = 100;
293 	port_range_hints[CONTROL_GAIN].LowerBound = -70;
294 	port_range_hints[CONTROL_GAIN].UpperBound = 20;
295 	port_range_hints[INPUT_0].HintDescriptor = 0;
296 	port_range_hints[OUTPUT_0].HintDescriptor = 0;
297 	mono_descriptor->instantiate = instantiate_Tremolo;
298 	mono_descriptor->connect_port = connect_port_Tremolo;
299 	mono_descriptor->activate = activate_Tremolo;
300 	mono_descriptor->run = run_Tremolo;
301 	mono_descriptor->run_adding = run_adding_Tremolo;
302 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_Tremolo;
303 	mono_descriptor->deactivate = NULL;
304 	mono_descriptor->cleanup = cleanup_Tremolo;
305 }
306 
307 
308 void
delete_descriptor(LADSPA_Descriptor * descriptor)309 delete_descriptor(LADSPA_Descriptor * descriptor) {
310 	unsigned long index;
311 	if (descriptor) {
312 		free((char *)descriptor->Label);
313 		free((char *)descriptor->Name);
314 		free((char *)descriptor->Maker);
315 		free((char *)descriptor->Copyright);
316 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
317 		for (index = 0; index < descriptor->PortCount; index++)
318 			free((char *)(descriptor->PortNames[index]));
319 		free((char **)descriptor->PortNames);
320 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
321 		free(descriptor);
322 	}
323 }
324 
325 
326 /* _fini() is called automatically when the library is unloaded. */
327 void
_fini()328 _fini() {
329 	delete_descriptor(mono_descriptor);
330 }
331 
332 
333 /* Return a descriptor of the requested plugin type. */
334 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)335 ladspa_descriptor(unsigned long Index) {
336 
337 	switch (Index) {
338 	case 0:
339 		return mono_descriptor;
340 	default:
341 		return NULL;
342 	}
343 }
344