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