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