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_deesser.c,v 1.7 2004/05/01 16:15:06 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         2147
33 
34 /* The port numbers for the plugin: */
35 
36 #define THRESHOLD       0
37 #define FREQ            1
38 #define SIDECHAIN       2
39 #define MONITOR         3
40 #define ATTENUAT        4
41 #define INPUT           5
42 #define OUTPUT          6
43 
44 
45 /* Total number of ports */
46 
47 #define PORTCOUNT_MONO   7
48 
49 
50 /* Bandwidth of sidechain lowpass/highpass filters */
51 #define SIDECH_BW       0.3f
52 
53 /* Used to hold 10 ms gain data, enough for sample rates up to 192 kHz */
54 #define RINGBUF_SIZE    2000
55 
56 
57 
58 /* 4 digits precision from 1.000 to 9.999 */
59 LADSPA_Data log10_table[9000];
60 
61 
62 /* The structure used to hold port connection information and state */
63 
64 typedef struct {
65 	LADSPA_Data * threshold;
66 	LADSPA_Data * audiomode;
67 	LADSPA_Data * freq;
68 	LADSPA_Data * sidechain;
69 	LADSPA_Data * monitor;
70 	LADSPA_Data * attenuat;
71 	LADSPA_Data * input;
72 	LADSPA_Data * output;
73 
74 	biquad sidech_lo_filter;
75 	biquad sidech_hi_filter;
76 	LADSPA_Data * ringbuffer;
77 	unsigned long buflen;
78 	unsigned long pos;
79 	LADSPA_Data sum;
80 	LADSPA_Data old_freq;
81 
82 	unsigned long sample_rate;
83 	LADSPA_Data run_adding_gain;
84 } DeEsser;
85 
86 
87 /* fast linear to decibel conversion using log10_table[] */
fast_lin2db(LADSPA_Data lin)88 LADSPA_Data fast_lin2db(LADSPA_Data lin) {
89 
90         unsigned long k;
91         int exp = 0;
92         LADSPA_Data mant = ABS(lin);
93 
94 	/* sanity checks */
95 	if (mant == 0.0f)
96 		return(-1.0f/0.0f); /* -inf */
97 	if (mant == 1.0f/0.0f) /* +inf */
98 		return(mant);
99 
100         while (mant < 1.0f) {
101                 mant *= 10;
102                 exp --;
103         }
104         while (mant >= 10.0f) {
105                 mant /= 10;
106                 exp ++;
107         }
108 
109         k = (mant - 0.999999f) * 1000.0f;
110         return 20.0f * (log10_table[k] + exp);
111 }
112 
113 
114 
115 /* Construct a new plugin instance. */
116 LADSPA_Handle
instantiate_DeEsser(const LADSPA_Descriptor * Descriptor,unsigned long SampleRate)117 instantiate_DeEsser(const LADSPA_Descriptor * Descriptor,
118 		    unsigned long             SampleRate) {
119 
120 	LADSPA_Handle * ptr;
121 
122 	if ((ptr = malloc(sizeof(DeEsser))) != NULL) {
123 		((DeEsser *)ptr)->sample_rate = SampleRate;
124 		((DeEsser *)ptr)->run_adding_gain = 1.0f;
125 
126 		/* init filters */
127 		biquad_init(&((DeEsser *)ptr)->sidech_lo_filter);
128 		biquad_init(&((DeEsser *)ptr)->sidech_hi_filter);
129 
130 		/* alloc mem for ringbuffer */
131 		if ((((DeEsser *)ptr)->ringbuffer =
132 		     calloc(RINGBUF_SIZE, sizeof(LADSPA_Data))) == NULL)
133 			return NULL;
134 
135                 /* 10 ms attenuation data is stored */
136 		((DeEsser *)ptr)->buflen = ((DeEsser *)ptr)->sample_rate / 100;
137 
138 		((DeEsser *)ptr)->pos = 0;
139 		((DeEsser *)ptr)->sum = 0.0f;
140 		((DeEsser *)ptr)->old_freq = 0;
141 
142 		return ptr;
143 	}
144 	return NULL;
145 }
146 
147 
148 void
activate_DeEsser(LADSPA_Handle Instance)149 activate_DeEsser(LADSPA_Handle Instance) {
150 
151 	DeEsser * ptr = (DeEsser *)Instance;
152 	unsigned long i;
153 
154 	for (i = 0; i < RINGBUF_SIZE; i++)
155 		ptr->ringbuffer[i] = 0.0f;
156 }
157 
158 
159 
160 
161 /* Connect a port to a data location. */
162 void
connect_port_DeEsser(LADSPA_Handle Instance,unsigned long Port,LADSPA_Data * DataLocation)163 connect_port_DeEsser(LADSPA_Handle Instance,
164 		     unsigned long Port,
165 		     LADSPA_Data * DataLocation) {
166 
167 	DeEsser * ptr;
168 
169 	ptr = (DeEsser *)Instance;
170 	switch (Port) {
171 	case THRESHOLD:
172 		ptr->threshold = DataLocation;
173 		break;
174 	case FREQ:
175 		ptr->freq = DataLocation;
176 		break;
177 	case SIDECHAIN:
178 		ptr->sidechain = DataLocation;
179 		break;
180 	case MONITOR:
181 		ptr->monitor = DataLocation;
182 		break;
183 	case ATTENUAT:
184 		ptr->attenuat = DataLocation;
185 		*(ptr->attenuat) = 0.0f;
186 		break;
187 	case INPUT:
188 		ptr->input = DataLocation;
189 		break;
190 	case OUTPUT:
191 		ptr->output = DataLocation;
192 		break;
193 	}
194 }
195 
196 
197 
198 void
run_DeEsser(LADSPA_Handle Instance,unsigned long SampleCount)199 run_DeEsser(LADSPA_Handle Instance,
200 	    unsigned long SampleCount) {
201 
202 	DeEsser * ptr = (DeEsser *)Instance;
203 
204 	LADSPA_Data * input = ptr->input;
205 	LADSPA_Data * output = ptr->output;
206 	LADSPA_Data threshold = LIMIT(*(ptr->threshold),-50.0f,10.0f);
207 	LADSPA_Data freq = LIMIT(*(ptr->freq),2000.0f,16000.0f);
208 	LADSPA_Data sidechain = LIMIT(*(ptr->sidechain),0.0f,1.0f);
209 	LADSPA_Data monitor = LIMIT(*(ptr->monitor),0.0f,1.0f);
210 	unsigned long sample_index;
211 
212 	LADSPA_Data in = 0;
213 	LADSPA_Data out = 0;
214 	LADSPA_Data sidech = 0;
215 	LADSPA_Data ampl_db = 0.0f;
216 	LADSPA_Data attn = 0.0f;
217 	LADSPA_Data max_attn = 0.0f;
218 
219 
220 	if (ptr->old_freq != freq) {
221 		lp_set_params(&ptr->sidech_lo_filter, freq, SIDECH_BW, ptr->sample_rate);
222 		hp_set_params(&ptr->sidech_hi_filter, freq, SIDECH_BW, ptr->sample_rate);
223 		ptr->old_freq = freq;
224 	}
225 
226 	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
227 
228 		in = *(input++);
229 
230 		/* process sidechain filters */
231 		sidech = biquad_run(&ptr->sidech_hi_filter, in);
232 		if (sidechain > 0.1f)
233 			sidech = biquad_run(&ptr->sidech_lo_filter, sidech);
234 
235 		ampl_db = fast_lin2db(sidech);
236 		if (ampl_db <= threshold)
237 			attn = 0.0f;
238 		else
239 			attn = -0.5f * (ampl_db - threshold);
240 
241 		ptr->sum += attn;
242 		ptr->sum -= push_buffer(attn, ptr->ringbuffer, ptr->buflen, &ptr->pos);
243 
244 		if (-1.0f * ptr->sum > max_attn)
245 			max_attn = -0.01f * ptr->sum;
246 
247 		in *= db2lin(ptr->sum / 100.0f);
248 
249 
250 		/* output selector */
251 		if (monitor > 0.1f)
252 			out = sidech;
253 		else
254 			out = in;
255 
256 		*(output++) = out;
257 		*(ptr->attenuat) = LIMIT(max_attn,0,10);
258 	}
259 }
260 
261 
262 void
set_run_adding_gain_DeEsser(LADSPA_Handle Instance,LADSPA_Data gain)263 set_run_adding_gain_DeEsser(LADSPA_Handle Instance, LADSPA_Data gain) {
264 
265 	DeEsser * ptr = (DeEsser *)Instance;
266 
267 	ptr->run_adding_gain = gain;
268 }
269 
270 
271 
272 void
run_adding_DeEsser(LADSPA_Handle Instance,unsigned long SampleCount)273 run_adding_DeEsser(LADSPA_Handle Instance,
274 		   unsigned long SampleCount) {
275 
276 	DeEsser * ptr = (DeEsser *)Instance;
277 
278 	LADSPA_Data * input = ptr->input;
279 	LADSPA_Data * output = ptr->output;
280 	LADSPA_Data threshold = LIMIT(*(ptr->threshold),-50.0f,10.0f);
281 	LADSPA_Data freq = LIMIT(*(ptr->freq),2000.0f,16000.0f);
282 	LADSPA_Data sidechain = LIMIT(*(ptr->sidechain),0.0f,1.0f);
283 	LADSPA_Data monitor = LIMIT(*(ptr->monitor),0.0f,1.0f);
284 	unsigned long sample_index;
285 
286 	LADSPA_Data in = 0;
287 	LADSPA_Data out = 0;
288 	LADSPA_Data sidech = 0;
289 	LADSPA_Data ampl_db = 0.0f;
290 	LADSPA_Data attn = 0.0f;
291 	LADSPA_Data max_attn = 0.0f;
292 
293 
294 	if (ptr->old_freq != freq) {
295 		lp_set_params(&ptr->sidech_lo_filter, freq, SIDECH_BW, ptr->sample_rate);
296 		hp_set_params(&ptr->sidech_hi_filter, freq, SIDECH_BW, ptr->sample_rate);
297 		ptr->old_freq = freq;
298 	}
299 
300 	for (sample_index = 0; sample_index < SampleCount; sample_index++) {
301 
302 		in = *(input++);
303 
304 		/* process sidechain filters */
305 		sidech = biquad_run(&ptr->sidech_hi_filter, in);
306 		if (sidechain > 0.1f)
307 			sidech = biquad_run(&ptr->sidech_lo_filter, sidech);
308 
309 		ampl_db = 20.0f * log10f(sidech);
310 		if (ampl_db <= threshold)
311 			attn = 0.0f;
312 		else
313 			attn = -0.5f * (ampl_db - threshold);
314 
315 		ptr->sum += attn;
316 		ptr->sum -= push_buffer(attn, ptr->ringbuffer, ptr->buflen, &ptr->pos);
317 
318 		if (-1.0f * ptr->sum > max_attn)
319 			max_attn = -0.01f * ptr->sum;
320 
321 		in *= db2lin(ptr->sum / 100.0f);
322 
323 
324 		/* output selector */
325 		if (monitor > 0.1f)
326 			out = sidech;
327 		else
328 			out = in;
329 
330 		*(output++) += ptr->run_adding_gain * out;
331 		*(ptr->attenuat) = LIMIT(max_attn,0,10);
332 	}
333 }
334 
335 
336 
337 /* Throw away a DeEsser effect instance. */
338 void
cleanup_DeEsser(LADSPA_Handle Instance)339 cleanup_DeEsser(LADSPA_Handle Instance) {
340 
341 	DeEsser * ptr = (DeEsser *)Instance;
342 	free(ptr->ringbuffer);
343 	free(Instance);
344 }
345 
346 
347 
348 LADSPA_Descriptor * mono_descriptor = NULL;
349 
350 
351 
352 /* _init() is called automatically when the plugin library is first
353    loaded. */
354 void
_init()355 _init() {
356 
357 	int i;
358 	char ** port_names;
359 	LADSPA_PortDescriptor * port_descriptors;
360 	LADSPA_PortRangeHint * port_range_hints;
361 
362 	if ((mono_descriptor =
363 	     (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
364 		exit(1);
365 
366 
367 	/* compute the log10 table */
368         for (i = 0; i < 9000; i++)
369                 log10_table[i] = log10f(1.0f + i / 1000.0f);
370 
371 
372 	mono_descriptor->UniqueID = ID_MONO;
373 	mono_descriptor->Label = strdup("tap_deesser");
374 	mono_descriptor->Properties = 0;
375 	mono_descriptor->Name = strdup("TAP DeEsser");
376 	mono_descriptor->Maker = strdup("Tom Szilagyi");
377 	mono_descriptor->Copyright = strdup("GPL");
378 	mono_descriptor->PortCount = PORTCOUNT_MONO;
379 
380 	if ((port_descriptors =
381 	     (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
382 		exit(1);
383 
384 	mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
385 	port_descriptors[THRESHOLD] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
386 	port_descriptors[FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
387 	port_descriptors[SIDECHAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
388 	port_descriptors[MONITOR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
389 	port_descriptors[ATTENUAT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
390 	port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
391 	port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
392 
393 	if ((port_names =
394 	     (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
395 		exit(1);
396 
397 	mono_descriptor->PortNames = (const char **)port_names;
398 	port_names[THRESHOLD] = strdup("Threshold Level [dB]");
399 	port_names[FREQ] = strdup("Frequency [Hz]");
400 	port_names[SIDECHAIN] = strdup("Sidechain Filter");
401 	port_names[MONITOR] = strdup("Monitor");
402 	port_names[ATTENUAT] = strdup("Attenuation [dB]");
403 	port_names[INPUT] = strdup("Input");
404 	port_names[OUTPUT] = strdup("Output");
405 
406 	if ((port_range_hints =
407 	     ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
408 		exit(1);
409 
410 	mono_descriptor->PortRangeHints	= (const LADSPA_PortRangeHint *)port_range_hints;
411 	port_range_hints[THRESHOLD].HintDescriptor =
412 		(LADSPA_HINT_BOUNDED_BELOW |
413 		 LADSPA_HINT_BOUNDED_ABOVE |
414 		 LADSPA_HINT_DEFAULT_0);
415 	port_range_hints[FREQ].HintDescriptor =
416 		(LADSPA_HINT_BOUNDED_BELOW |
417 		 LADSPA_HINT_BOUNDED_ABOVE |
418 		 LADSPA_HINT_DEFAULT_LOW);
419 	port_range_hints[SIDECHAIN].HintDescriptor =
420 		(LADSPA_HINT_BOUNDED_BELOW |
421 		 LADSPA_HINT_BOUNDED_ABOVE |
422 		 LADSPA_HINT_INTEGER |
423 		 LADSPA_HINT_DEFAULT_0);
424 	port_range_hints[MONITOR].HintDescriptor =
425 		(LADSPA_HINT_BOUNDED_BELOW |
426 		 LADSPA_HINT_BOUNDED_ABOVE |
427 		 LADSPA_HINT_INTEGER |
428 		 LADSPA_HINT_DEFAULT_0);
429 	port_range_hints[ATTENUAT].HintDescriptor =
430 		(LADSPA_HINT_BOUNDED_BELOW |
431 		 LADSPA_HINT_BOUNDED_ABOVE |
432 		 LADSPA_HINT_DEFAULT_0);
433 	port_range_hints[THRESHOLD].LowerBound = -50;
434 	port_range_hints[THRESHOLD].UpperBound = 10;
435 	port_range_hints[FREQ].LowerBound = 2000;
436 	port_range_hints[FREQ].UpperBound = 16000;
437 	port_range_hints[SIDECHAIN].LowerBound = 0.0f;
438 	port_range_hints[SIDECHAIN].UpperBound = 1.01f;
439 	port_range_hints[MONITOR].LowerBound = 0.0f;
440 	port_range_hints[MONITOR].UpperBound = 1.01f;
441 	port_range_hints[ATTENUAT].LowerBound = 0.0f;
442 	port_range_hints[ATTENUAT].UpperBound = 10.0f;
443 	port_range_hints[INPUT].HintDescriptor = 0;
444 	port_range_hints[OUTPUT].HintDescriptor = 0;
445 	mono_descriptor->instantiate = instantiate_DeEsser;
446 	mono_descriptor->connect_port = connect_port_DeEsser;
447 	mono_descriptor->activate = activate_DeEsser;
448 	mono_descriptor->run = run_DeEsser;
449 	mono_descriptor->run_adding = run_adding_DeEsser;
450 	mono_descriptor->set_run_adding_gain = set_run_adding_gain_DeEsser;
451 	mono_descriptor->deactivate = NULL;
452 	mono_descriptor->cleanup = cleanup_DeEsser;
453 }
454 
455 
456 void
delete_descriptor(LADSPA_Descriptor * descriptor)457 delete_descriptor(LADSPA_Descriptor * descriptor) {
458 	unsigned long index;
459 	if (descriptor) {
460 		free((char *)descriptor->Label);
461 		free((char *)descriptor->Name);
462 		free((char *)descriptor->Maker);
463 		free((char *)descriptor->Copyright);
464 		free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
465 		for (index = 0; index < descriptor->PortCount; index++)
466 			free((char *)(descriptor->PortNames[index]));
467 		free((char **)descriptor->PortNames);
468 		free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
469 		free(descriptor);
470 	}
471 }
472 
473 
474 /* _fini() is called automatically when the library is unloaded. */
475 void
_fini()476 _fini() {
477 	delete_descriptor(mono_descriptor);
478 }
479 
480 
481 /* Return a descriptor of the requested plugin type. */
482 const LADSPA_Descriptor *
ladspa_descriptor(unsigned long Index)483 ladspa_descriptor(unsigned long Index) {
484 
485 	switch (Index) {
486 	case 0:
487 		return mono_descriptor;
488 	default:
489 		return NULL;
490 	}
491 }
492