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_limiter.c,v 1.5 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         2145
33 
34 /* The port numbers for the plugin: */
35 
36 #define LIMIT_VOL       0
37 #define OUT_VOL         1
38 #define LATENCY         2
39 #define INPUT           3
40 #define OUTPUT          4
41 
42 /* Total number of ports */
43 
44 #define PORTCOUNT_MONO   5
45 
46 
47 /* Size of a ringbuffer that must be large enough to hold audio
48  * between two zero-crosses in any case (or you'll hear
49  * distortion). 40 Hz sound at 192kHz yields a half-period of 2400
50  * samples, so this should be enough.
51  */
52 #define RINGBUF_SIZE 2500
53 
54 
55 /* The structure used to hold port connection information and state */
56 
57 typedef struct {
58 	LADSPA_Data * limit_vol;
59 	LADSPA_Data * out_vol;
60 	LADSPA_Data * latency;
61 	LADSPA_Data * input;
62 	LADSPA_Data * output;
63 
64 	LADSPA_Data * ringbuffer;
65 	unsigned long buflen;
66 	unsigned long pos;
67 	unsigned long ready_num;
68 
69 	unsigned long sample_rate;
70 	LADSPA_Data run_adding_gain;
71 } Limiter;
72 
73 
74 
75 
76 /* Construct a new plugin instance. */
77 LADSPA_Handle
instantiate_Limiter(const LADSPA_Descriptor * Descriptor,unsigned long sample_rate)78 instantiate_Limiter(const LADSPA_Descriptor * Descriptor,
79 		    unsigned long             sample_rate) {
80 
81 	LADSPA_Handle * ptr;
82 
83 	if ((ptr = malloc(sizeof(Limiter))) != NULL) {
84 		((Limiter *)ptr)->sample_rate = sample_rate;
85 		((Limiter *)ptr)->run_adding_gain = 1.0f;
86 
87 		if ((((Limiter *)ptr)->ringbuffer =
88 		     calloc(RINGBUF_SIZE, sizeof(LADSPA_Data))) == NULL)
89 			return NULL;
90 
91 		/* 80 Hz is the lowest frequency with which zero-crosses were
92 		 * observed to occur (this corresponds to 40 Hz signal frequency).
93 		 */
94 		((Limiter *)ptr)->buflen = ((Limiter *)ptr)->sample_rate / 80;
95 
96 		((Limiter *)ptr)->pos = 0;
97 		((Limiter *)ptr)->ready_num = 0;
98 
99 		return ptr;
100 	}
101        	return NULL;
102 }
103 
104 
105 void
activate_Limiter(LADSPA_Handle Instance)106 activate_Limiter(LADSPA_Handle Instance) {
107 
108 	Limiter * ptr = (Limiter *)Instance;
109 	unsigned long i;
110 
111 	for (i = 0; i < RINGBUF_SIZE; i++)
112 		ptr->ringbuffer[i] = 0.0f;
113 }
114 
115 
116 
117 
118 
119 /* Connect a port to a data location. */
120 void
connect_port_Limiter(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)121 connect_port_Limiter(LADSPA_Handle Instance,
122 		     unsigned long Port,
123 		     LADSPA_Data * DataLocation) {
124 
125 	Limiter * ptr = (Limiter *)Instance;
126 
127 	switch (Port) {
128 	case LIMIT_VOL:
129 		ptr->limit_vol = DataLocation;
130 		break;
131 	case OUT_VOL:
132 		ptr->out_vol = DataLocation;
133 		break;
134 	case LATENCY:
135 		ptr->latency = DataLocation;
136 		*(ptr->latency) = ptr->buflen;  /* IS THIS LEGAL? */
137 		break;
138 	case INPUT:
139 		ptr->input = DataLocation;
140 		break;
141 	case OUTPUT:
142 		ptr->output = DataLocation;
143 		break;
144 	}
145 }
146 
147 
148 
149 void
run_Limiter(LADSPA_Handle Instance,unsigned long SampleCount)150 run_Limiter(LADSPA_Handle Instance,
151 	    unsigned long SampleCount) {
152 
153 	Limiter * ptr = (Limiter *)Instance;
154 
155 	LADSPA_Data * input = ptr->input;
156 	LADSPA_Data * output = ptr->output;
157 	LADSPA_Data limit_vol = db2lin(LIMIT(*(ptr->limit_vol),-30.0f,20.0f));
158 	LADSPA_Data out_vol = db2lin(LIMIT(*(ptr->out_vol),-30.0f,20.0f));
159 	unsigned long sample_index;
160 	unsigned long sample_count = SampleCount;
161 	unsigned long index_offs = 0;
162 	unsigned long i;
163 	LADSPA_Data max_value = 0;
164 	LADSPA_Data section_gain = 0;
165 	unsigned long run_length;
166 	unsigned long total_length = 0;
167 
168 
169 	while (total_length < sample_count) {
170 
171 		run_length = ptr->buflen;
172 		if (total_length + run_length > sample_count)
173 			run_length = sample_count - total_length;
174 
175 		while (ptr->ready_num < run_length) {
176 			if (read_buffer(ptr->ringbuffer, ptr->buflen,
177 					ptr->pos, ptr->ready_num) >= 0.0f) {
178 				index_offs = 0;
179 				while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
180 						    ptr->ready_num + index_offs) >= 0.0f) &&
181 				       (ptr->ready_num + index_offs < run_length)) {
182 					index_offs++;
183 				}
184 			} else {
185 				index_offs = 0;
186 				while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
187 						    ptr->ready_num + index_offs) <= 0.0f) &&
188 				       (ptr->ready_num + index_offs < run_length)) {
189 					index_offs++;
190 				}
191 			}
192 
193 			/* search for max value in scanned halfcycle */
194 			max_value = 0;
195 			for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
196 				if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen,
197 						     ptr->pos, i)) > max_value)
198 					max_value = fabs(read_buffer(ptr->ringbuffer,
199 								     ptr->buflen, ptr->pos, i));
200 			}
201 			section_gain = limit_vol / max_value;
202 			if (max_value > limit_vol)
203 				for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
204 					write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen,
205 								 ptr->pos, i) * section_gain,
206 						     ptr->ringbuffer, ptr->buflen, ptr->pos, i);
207 				}
208 			ptr->ready_num += index_offs;
209 		}
210 
211 		/* push run_length values out of ringbuffer, feed with input */
212 		for (sample_index = 0; sample_index < run_length; sample_index++) {
213 			*(output++) = out_vol *
214 				push_buffer(*(input++), ptr->ringbuffer,
215 					    ptr->buflen, &(ptr->pos));
216 		}
217 		ptr->ready_num -= run_length;
218 		total_length += run_length;
219 	}
220 	*(ptr->latency) = ptr->buflen;
221 }
222 
223 
224 
225 void
set_run_adding_gain_Limiter(LADSPA_Handle Instance,LADSPA_Data gain)226 set_run_adding_gain_Limiter(LADSPA_Handle Instance, LADSPA_Data gain) {
227 
228 	Limiter * ptr = (Limiter *)Instance;
229 
230 	ptr->run_adding_gain = gain;
231 }
232 
233 
234 
235 void
run_adding_Limiter(LADSPA_Handle Instance,unsigned long SampleCount)236 run_adding_Limiter(LADSPA_Handle Instance,
237 		   unsigned long SampleCount) {
238 
239 	Limiter * ptr = (Limiter *)Instance;
240 
241 	LADSPA_Data * input = ptr->input;
242 	LADSPA_Data * output = ptr->output;
243 	LADSPA_Data limit_vol = db2lin(LIMIT(*(ptr->limit_vol),-30.0f,20.0f));
244 	LADSPA_Data out_vol = db2lin(LIMIT(*(ptr->out_vol),-30.0f,20.0f));
245 	unsigned long sample_index;
246 	unsigned long sample_count = SampleCount;
247 	unsigned long index_offs = 0;
248 	unsigned long i;
249 	LADSPA_Data max_value = 0;
250 	LADSPA_Data section_gain = 0;
251 	unsigned long run_length;
252 	unsigned long total_length = 0;
253 
254 
255 	while (total_length < sample_count) {
256 
257 		run_length = ptr->buflen;
258 		if (total_length + run_length > sample_count)
259 			run_length = sample_count - total_length;
260 
261 		while (ptr->ready_num < run_length) {
262 			if (read_buffer(ptr->ringbuffer, ptr->buflen,
263 					ptr->pos, ptr->ready_num) >= 0.0f) {
264 				index_offs = 0;
265 				while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
266 						    ptr->ready_num + index_offs) >= 0.0f) &&
267 				       (ptr->ready_num + index_offs < run_length)) {
268 					index_offs++;
269 				}
270 			} else {
271 				index_offs = 0;
272 				while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
273 						    ptr->ready_num + index_offs) <= 0.0f) &&
274 				       (ptr->ready_num + index_offs < run_length)) {
275 					index_offs++;
276 				}
277 			}
278 
279 			/* search for max value in scanned halfcycle */
280 			max_value = 0;
281 			for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
282 				if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen,
283 						     ptr->pos, i)) > max_value)
284 					max_value = fabs(read_buffer(ptr->ringbuffer,
285 								     ptr->buflen, ptr->pos, i));
286 			}
287 			section_gain = limit_vol / max_value;
288 			if (max_value > limit_vol)
289 				for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
290 					write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen,
291 								 ptr->pos, i) * section_gain,
292 						     ptr->ringbuffer, ptr->buflen, ptr->pos, i);
293 				}
294 			ptr->ready_num += index_offs;
295 		}
296 
297 		/* push run_length values out of ringbuffer, feed with input */
298 		for (sample_index = 0; sample_index < run_length; sample_index++) {
299 			*(output++) += ptr->run_adding_gain * out_vol *
300 				push_buffer(*(input++), ptr->ringbuffer,
301 					    ptr->buflen, &(ptr->pos));
302 		}
303 		ptr->ready_num -= run_length;
304 		total_length += run_length;
305 	}
306 	*(ptr->latency) = ptr->buflen;
307 }
308 
309 
310 
311 
312 /* Throw away a Limiter effect instance. */
313 void
cleanup_Limiter(LADSPA_Handle Instance)314 cleanup_Limiter(LADSPA_Handle Instance) {
315 
316 	Limiter * ptr = (Limiter *)Instance;
317 	free(ptr->ringbuffer);
318 	free(Instance);
319 }
320 
321 
322 
323 LADSPA_Descriptor * mono_descriptor = NULL;
324 
325 
326 
327 /* __attribute__((constructor)) tap_init() is called automatically when the plugin library is first
328    loaded. */
329 void
tap_init()330 __attribute__((constructor)) tap_init() {
331 
332 	char ** port_names;
333 	LADSPA_PortDescriptor * port_descriptors;
334 	LADSPA_PortRangeHint * port_range_hints;
335 
336 	if ((mono_descriptor =
337 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
338 		exit(1);
339 
340 
341 
342 	mono_descriptor->UniqueID = ID_MONO;
343 	mono_descriptor->Label = strdup("tap_limiter");
344 	mono_descriptor->Properties = 0;
345 	mono_descriptor->Name = strdup("TAP Scaling Limiter");
346 	mono_descriptor->Maker = strdup("Tom Szilagyi");
347 	mono_descriptor->Copyright = strdup("GPL");
348 	mono_descriptor->PortCount = PORTCOUNT_MONO;
349 
350 	if ((port_descriptors =
351 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
352 		exit(1);
353 
354 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
355 	port_descriptors[LIMIT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
356 	port_descriptors[OUT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
357 	port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
358 	port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
359 	port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
360 
361 	if ((port_names =
362 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
363 		exit(1);
364 
365 	mono_descriptor->PortNames = (const char **)port_names;
366 	port_names[LIMIT_VOL] = strdup("Limit Level [dB]");
367 	port_names[OUT_VOL] = strdup("Output Volume [dB]");
368 	port_names[LATENCY] = strdup("latency");
369 	port_names[INPUT] = strdup("Input");
370 	port_names[OUTPUT] = strdup("Output");
371 
372 	if ((port_range_hints =
373 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
374 		exit(1);
375 
376 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
377 	port_range_hints[LIMIT_VOL].HintDescriptor =
378 		(LADSPA_HINT_BOUNDED_BELOW |
379 		 LADSPA_HINT_BOUNDED_ABOVE |
380 		 LADSPA_HINT_DEFAULT_0);
381 	port_range_hints[OUT_VOL].HintDescriptor =
382 		(LADSPA_HINT_BOUNDED_BELOW |
383 		 LADSPA_HINT_BOUNDED_ABOVE |
384 		 LADSPA_HINT_DEFAULT_0);
385 	port_range_hints[LATENCY].HintDescriptor =
386 		(LADSPA_HINT_BOUNDED_BELOW |
387 		 LADSPA_HINT_BOUNDED_ABOVE |
388 		 LADSPA_HINT_DEFAULT_MAXIMUM);
389 	port_range_hints[LIMIT_VOL].LowerBound = -30;
390 	port_range_hints[LIMIT_VOL].UpperBound = +20;
391 	port_range_hints[OUT_VOL].LowerBound = -30;
392 	port_range_hints[OUT_VOL].UpperBound = +20;
393 	port_range_hints[LATENCY].LowerBound = 0;
394 	port_range_hints[LATENCY].UpperBound = RINGBUF_SIZE + 0.1f;
395 	port_range_hints[INPUT].HintDescriptor = 0;
396 	port_range_hints[OUTPUT].HintDescriptor = 0;
397 	mono_descriptor->instantiate = instantiate_Limiter;
398 	mono_descriptor->connect_port = connect_port_Limiter;
399 	mono_descriptor->activate = activate_Limiter;
400 	mono_descriptor->run = run_Limiter;
401 	mono_descriptor->run_adding = run_adding_Limiter;
402 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_Limiter;
403 	mono_descriptor->deactivate = NULL;
404 	mono_descriptor->cleanup = cleanup_Limiter;
405 }
406 
407 
408 void
delete_descriptor(LADSPA_Descriptor * descriptor)409 delete_descriptor(LADSPA_Descriptor * descriptor) {
410 	unsigned long index;
411 	if (descriptor) {
412 		free((char *)descriptor->Label);
413 		free((char *)descriptor->Name);
414 		free((char *)descriptor->Maker);
415 		free((char *)descriptor->Copyright);
416 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
417 		for (index = 0; index < descriptor->PortCount; index++)
418 			free((char *)(descriptor->PortNames[index]));
419 		free((char **)descriptor->PortNames);
420 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
421 		free(descriptor);
422 	}
423 }
424 
425 
426 /* __attribute__((destructor)) tap_fini() is called automatically when the library is unloaded. */
427 void
tap_fini()428 __attribute__((destructor)) tap_fini() {
429 	delete_descriptor(mono_descriptor);
430 }
431 
432 
433 /* Return a descriptor of the requested plugin type. */
434 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)435 ladspa_descriptor(unsigned long Index) {
436 
437 	switch (Index) {
438 	case 0:
439 		return mono_descriptor;
440 	default:
441 		return NULL;
442 	}
443 }
444