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.6 2012/07/08 14:19:35 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
db_put(DB * db,int k,int v)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
78 instantiate_Limiter(const LADSPA_Descriptor * Descriptor,
79 		    unsigned long             sample_rate) {
80 
81 	LADSPA_Handle * ptr;
expect_cursor_get(DBC * cursor,int k,int v)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 	}
expect_cursor_set(DBC * cursor,int k,int expectr)101        	return NULL;
102 }
103 
104 
105 void
106 activate_Limiter(LADSPA_Handle Instance) {
107 
108 	Limiter * ptr = (Limiter *)Instance;
expect_cursor_get_current(DBC * cursor,int k,int v)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
121 connect_port_Limiter(LADSPA_Handle Instance,
test_icdi_search(int n,int dup_mode)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
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 				do {
180 					index_offs++;
181 					if (ptr->ready_num + index_offs == run_length) {
182 						/*
183 						 * No more zero-crossing point in this chunk.
184 						 * Fetch more samples unless we are at the last one.
185 						 */
186 						if (ptr->ready_num != 0) {
187 							run_length = ptr->ready_num;
188 							goto push;
189 						}
190 						break;
191 					}
192 				} while (read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
193 						     ptr->ready_num + index_offs) >= 0.0f);
194 			} else {
195 				index_offs = 0;
test_main(int argc,char * const argv[])196 				do {
197 					index_offs++;
198 					if (ptr->ready_num + index_offs == run_length) {
199 						/*
200 						 * No more zero-crossing point in this chunk.
201 						 * Fetch more samples unless we are at the last one.
202 						 */
203 						if (ptr->ready_num != 0) {
204 							run_length = ptr->ready_num;
205 							goto push;
206 						}
207 						break;
208 					}
209 				} while (read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
210 						     ptr->ready_num + index_offs) < 0.0f);
211 			}
212 
213 			/* search for max value in scanned halfcycle */
214 			max_value = 0;
215 			for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
216 				if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen,
217 						     ptr->pos, i)) > max_value)
218 					max_value = fabs(read_buffer(ptr->ringbuffer,
219 								     ptr->buflen, ptr->pos, i));
220 			}
221 			section_gain = limit_vol / max_value;
222 			if (max_value > limit_vol)
223 				for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
224 					write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen,
225 								 ptr->pos, i) * section_gain,
226 						     ptr->ringbuffer, ptr->buflen, ptr->pos, i);
227 				}
228 			ptr->ready_num += index_offs;
229 		}
230 
231 	push:
232 		/* push run_length values out of ringbuffer, feed with input */
233 		for (sample_index = 0; sample_index < run_length; sample_index++) {
234 			*(output++) = out_vol *
235 				push_buffer(*(input++), ptr->ringbuffer,
236 					    ptr->buflen, &(ptr->pos));
237 		}
238 		ptr->ready_num -= run_length;
239 		total_length += run_length;
240 	}
241 	*(ptr->latency) = ptr->buflen;
242 }
243 
244 
245 
246 void
247 set_run_adding_gain_Limiter(LADSPA_Handle Instance, LADSPA_Data gain) {
248 
249 	Limiter * ptr = (Limiter *)Instance;
250 
251 	ptr->run_adding_gain = gain;
252 }
253 
254 
255 
256 void
257 run_adding_Limiter(LADSPA_Handle Instance,
258 		   unsigned long SampleCount) {
259 
260 	Limiter * ptr = (Limiter *)Instance;
261 
262 	LADSPA_Data * input = ptr->input;
263 	LADSPA_Data * output = ptr->output;
264 	LADSPA_Data limit_vol = db2lin(LIMIT(*(ptr->limit_vol),-30.0f,20.0f));
265 	LADSPA_Data out_vol = db2lin(LIMIT(*(ptr->out_vol),-30.0f,20.0f));
266 	unsigned long sample_index;
267 	unsigned long sample_count = SampleCount;
268 	unsigned long index_offs = 0;
269 	unsigned long i;
270 	LADSPA_Data max_value = 0;
271 	LADSPA_Data section_gain = 0;
272 	unsigned long run_length;
273 	unsigned long total_length = 0;
274 
275 
276 	while (total_length < sample_count) {
277 
278 		run_length = ptr->buflen;
279 		if (total_length + run_length > sample_count)
280 			run_length = sample_count - total_length;
281 
282 		while (ptr->ready_num < run_length) {
283 			if (read_buffer(ptr->ringbuffer, ptr->buflen,
284 					ptr->pos, ptr->ready_num) >= 0.0f) {
285 				index_offs = 0;
286 				do {
287 					index_offs++;
288 					if (ptr->ready_num + index_offs == run_length) {
289 						/*
290 						 * No more zero-crossing point in this chunk.
291 						 * Fetch more samples unless we are at the last one.
292 						 */
293 						if (ptr->ready_num != 0) {
294 							run_length = ptr->ready_num;
295 							goto push;
296 						}
297 						break;
298 					}
299 				} while (read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
300 						     ptr->ready_num + index_offs) >= 0.0f);
301 			} else {
302 				index_offs = 0;
303 				do {
304 					index_offs++;
305 					if (ptr->ready_num + index_offs == run_length) {
306 						/*
307 						 * No more zero-crossing point in this chunk.
308 						 * Fetch more samples unless we are at the last one.
309 						 */
310 						if (ptr->ready_num != 0) {
311 							run_length = ptr->ready_num;
312 							goto push;
313 						}
314 						break;
315 					}
316 				} while (read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos,
317 						     ptr->ready_num + index_offs) < 0.0f);
318 			}
319 
320 			/* search for max value in scanned halfcycle */
321 			max_value = 0;
322 			for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
323 				if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen,
324 						     ptr->pos, i)) > max_value)
325 					max_value = fabs(read_buffer(ptr->ringbuffer,
326 								     ptr->buflen, ptr->pos, i));
327 			}
328 			section_gain = limit_vol / max_value;
329 			if (max_value > limit_vol)
330 				for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) {
331 					write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen,
332 								 ptr->pos, i) * section_gain,
333 						     ptr->ringbuffer, ptr->buflen, ptr->pos, i);
334 				}
335 			ptr->ready_num += index_offs;
336 		}
337 
338 	push:
339 		/* push run_length values out of ringbuffer, feed with input */
340 		for (sample_index = 0; sample_index < run_length; sample_index++) {
341 			*(output++) += ptr->run_adding_gain * out_vol *
342 				push_buffer(*(input++), ptr->ringbuffer,
343 					    ptr->buflen, &(ptr->pos));
344 		}
345 		ptr->ready_num -= run_length;
346 		total_length += run_length;
347 	}
348 	*(ptr->latency) = ptr->buflen;
349 }
350 
351 
352 
353 
354 /* Throw away a Limiter effect instance. */
355 void
356 cleanup_Limiter(LADSPA_Handle Instance) {
357 
358 	Limiter * ptr = (Limiter *)Instance;
359 	free(ptr->ringbuffer);
360 	free(Instance);
361 }
362 
363 
364 
365 LADSPA_Descriptor * mono_descriptor = NULL;
366 
367 
368 
369 /* _init() is called automatically when the plugin library is first
370    loaded. */
371 void
372 _init() {
373 
374 	char ** port_names;
375 	LADSPA_PortDescriptor * port_descriptors;
376 	LADSPA_PortRangeHint * port_range_hints;
377 
378 	if ((mono_descriptor =
379 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
380 		exit(1);
381 
382 
383 
384 	mono_descriptor->UniqueID = ID_MONO;
385 	mono_descriptor->Label = strdup("tap_limiter");
386 	mono_descriptor->Properties = 0;
387 	mono_descriptor->Name = strdup("TAP Scaling Limiter");
388 	mono_descriptor->Maker = strdup("Tom Szilagyi");
389 	mono_descriptor->Copyright = strdup("GPL");
390 	mono_descriptor->PortCount = PORTCOUNT_MONO;
391 
392 	if ((port_descriptors =
393 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
394 		exit(1);
395 
396 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
397 	port_descriptors[LIMIT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
398 	port_descriptors[OUT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
399 	port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
400 	port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
401 	port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
402 
403 	if ((port_names =
404 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
405 		exit(1);
406 
407 	mono_descriptor->PortNames = (const char **)port_names;
408 	port_names[LIMIT_VOL] = strdup("Limit Level [dB]");
409 	port_names[OUT_VOL] = strdup("Output Volume [dB]");
410 	port_names[LATENCY] = strdup("latency");
411 	port_names[INPUT] = strdup("Input");
412 	port_names[OUTPUT] = strdup("Output");
413 
414 	if ((port_range_hints =
415 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
416 		exit(1);
417 
418 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
419 	port_range_hints[LIMIT_VOL].HintDescriptor =
420 		(LADSPA_HINT_BOUNDED_BELOW |
421 		 LADSPA_HINT_BOUNDED_ABOVE |
422 		 LADSPA_HINT_DEFAULT_0);
423 	port_range_hints[OUT_VOL].HintDescriptor =
424 		(LADSPA_HINT_BOUNDED_BELOW |
425 		 LADSPA_HINT_BOUNDED_ABOVE |
426 		 LADSPA_HINT_DEFAULT_0);
427 	port_range_hints[LATENCY].HintDescriptor =
428 		(LADSPA_HINT_BOUNDED_BELOW |
429 		 LADSPA_HINT_BOUNDED_ABOVE |
430 		 LADSPA_HINT_DEFAULT_MAXIMUM);
431 	port_range_hints[LIMIT_VOL].LowerBound = -30;
432 	port_range_hints[LIMIT_VOL].UpperBound = +20;
433 	port_range_hints[OUT_VOL].LowerBound = -30;
434 	port_range_hints[OUT_VOL].UpperBound = +20;
435 	port_range_hints[LATENCY].LowerBound = 0;
436 	port_range_hints[LATENCY].UpperBound = RINGBUF_SIZE + 0.1f;
437 	port_range_hints[INPUT].HintDescriptor = 0;
438 	port_range_hints[OUTPUT].HintDescriptor = 0;
439 	mono_descriptor->instantiate = instantiate_Limiter;
440 	mono_descriptor->connect_port = connect_port_Limiter;
441 	mono_descriptor->activate = activate_Limiter;
442 	mono_descriptor->run = run_Limiter;
443 	mono_descriptor->run_adding = run_adding_Limiter;
444 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_Limiter;
445 	mono_descriptor->deactivate = NULL;
446 	mono_descriptor->cleanup = cleanup_Limiter;
447 }
448 
449 
450 void
451 delete_descriptor(LADSPA_Descriptor * descriptor) {
452 	unsigned long index;
453 	if (descriptor) {
454 		free((char *)descriptor->Label);
455 		free((char *)descriptor->Name);
456 		free((char *)descriptor->Maker);
457 		free((char *)descriptor->Copyright);
458 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
459 		for (index = 0; index < descriptor->PortCount; index++)
460 			free((char *)(descriptor->PortNames[index]));
461 		free((char **)descriptor->PortNames);
462 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
463 		free(descriptor);
464 	}
465 }
466 
467 
468 /* _fini() is called automatically when the library is unloaded. */
469 void
470 _fini() {
471 	delete_descriptor(mono_descriptor);
472 }
473 
474 
475 /* Return a descriptor of the requested plugin type. */
476 const LADSPA_Descriptor *
477 ladspa_descriptor(unsigned long Index) {
478 
479 	switch (Index) {
480 	case 0:
481 		return mono_descriptor;
482 	default:
483 		return NULL;
484 	}
485 }
486