1 #include <stdlib.h>
2 #include <string.h>
3 #ifndef WIN32
4 #include "config.h"
5 #endif
6
7 #ifdef ENABLE_NLS
8 #include <libintl.h>
9 #endif
10
11 #define _ISOC9X_SOURCE 1
12 #define _ISOC99_SOURCE 1
13 #define __USE_ISOC99 1
14 #define __USE_ISOC9X 1
15
16 #include <math.h>
17
18 #include "ladspa.h"
19
20 #ifdef WIN32
21 #define _WINDOWS_DLL_EXPORT_ __declspec(dllexport)
22 int bIsFirstTime = 1;
23 static void __attribute__((constructor)) swh_init(); // forward declaration
24 #else
25 #define _WINDOWS_DLL_EXPORT_
26 #endif
27
28 #line 10 "sc4m_1916.xml"
29
30 #include "util/db.h"
31 #include "util/rms.h"
32
33 #define A_TBL 256
34
35 #define SC4M_RMS_PEAK 0
36 #define SC4M_ATTACK 1
37 #define SC4M_RELEASE 2
38 #define SC4M_THRESHOLD 3
39 #define SC4M_RATIO 4
40 #define SC4M_KNEE 5
41 #define SC4M_MAKEUP_GAIN 6
42 #define SC4M_AMPLITUDE 7
43 #define SC4M_GAIN_RED 8
44 #define SC4M_INPUT 9
45 #define SC4M_OUTPUT 10
46
47 static LADSPA_Descriptor *sc4mDescriptor = NULL;
48
49 typedef struct {
50 LADSPA_Data *rms_peak;
51 LADSPA_Data *attack;
52 LADSPA_Data *release;
53 LADSPA_Data *threshold;
54 LADSPA_Data *ratio;
55 LADSPA_Data *knee;
56 LADSPA_Data *makeup_gain;
57 LADSPA_Data *amplitude;
58 LADSPA_Data *gain_red;
59 LADSPA_Data *input;
60 LADSPA_Data *output;
61 float amp;
62 float * as;
63 unsigned int count;
64 float env;
65 float env_peak;
66 float env_rms;
67 float gain;
68 float gain_t;
69 rms_env * rms;
70 float sum;
71 LADSPA_Data run_adding_gain;
72 } Sc4m;
73
74 _WINDOWS_DLL_EXPORT_
ladspa_descriptor(unsigned long index)75 const LADSPA_Descriptor *ladspa_descriptor(unsigned long index) {
76
77 #ifdef WIN32
78 if (bIsFirstTime) {
79 swh_init();
80 bIsFirstTime = 0;
81 }
82 #endif
83 switch (index) {
84 case 0:
85 return sc4mDescriptor;
86 default:
87 return NULL;
88 }
89 }
90
cleanupSc4m(LADSPA_Handle instance)91 static void cleanupSc4m(LADSPA_Handle instance) {
92 #line 46 "sc4m_1916.xml"
93 Sc4m *plugin_data = (Sc4m *)instance;
94 rms_env_free(plugin_data->rms);
95 free(plugin_data->as);
96 free(instance);
97 }
98
connectPortSc4m(LADSPA_Handle instance,unsigned long port,LADSPA_Data * data)99 static void connectPortSc4m(
100 LADSPA_Handle instance,
101 unsigned long port,
102 LADSPA_Data *data) {
103 Sc4m *plugin;
104
105 plugin = (Sc4m *)instance;
106 switch (port) {
107 case SC4M_RMS_PEAK:
108 plugin->rms_peak = data;
109 break;
110 case SC4M_ATTACK:
111 plugin->attack = data;
112 break;
113 case SC4M_RELEASE:
114 plugin->release = data;
115 break;
116 case SC4M_THRESHOLD:
117 plugin->threshold = data;
118 break;
119 case SC4M_RATIO:
120 plugin->ratio = data;
121 break;
122 case SC4M_KNEE:
123 plugin->knee = data;
124 break;
125 case SC4M_MAKEUP_GAIN:
126 plugin->makeup_gain = data;
127 break;
128 case SC4M_AMPLITUDE:
129 plugin->amplitude = data;
130 break;
131 case SC4M_GAIN_RED:
132 plugin->gain_red = data;
133 break;
134 case SC4M_INPUT:
135 plugin->input = data;
136 break;
137 case SC4M_OUTPUT:
138 plugin->output = data;
139 break;
140 }
141 }
142
instantiateSc4m(const LADSPA_Descriptor * descriptor,unsigned long s_rate)143 static LADSPA_Handle instantiateSc4m(
144 const LADSPA_Descriptor *descriptor,
145 unsigned long s_rate) {
146 Sc4m *plugin_data = (Sc4m *)calloc(1, sizeof(Sc4m));
147 float amp;
148 float *as = NULL;
149 unsigned int count;
150 float env;
151 float env_peak;
152 float env_rms;
153 float gain;
154 float gain_t;
155 rms_env *rms = NULL;
156 float sum;
157
158 #line 23 "sc4m_1916.xml"
159 unsigned int i;
160 float sample_rate = (float)s_rate;
161
162 rms = rms_env_new();
163 sum = 0.0f;
164 amp = 0.0f;
165 gain = 0.0f;
166 gain_t = 0.0f;
167 env = 0.0f;
168 env_rms = 0.0f;
169 env_peak = 0.0f;
170 count = 0;
171
172 as = malloc(A_TBL * sizeof(float));
173 as[0] = 1.0f;
174 for (i=1; i<A_TBL; i++) {
175 as[i] = expf(-1.0f / (sample_rate * (float)i / (float)A_TBL));
176 }
177
178 db_init();
179
180 plugin_data->amp = amp;
181 plugin_data->as = as;
182 plugin_data->count = count;
183 plugin_data->env = env;
184 plugin_data->env_peak = env_peak;
185 plugin_data->env_rms = env_rms;
186 plugin_data->gain = gain;
187 plugin_data->gain_t = gain_t;
188 plugin_data->rms = rms;
189 plugin_data->sum = sum;
190
191 return (LADSPA_Handle)plugin_data;
192 }
193
194 #undef buffer_write
195 #undef RUN_ADDING
196 #undef RUN_REPLACING
197
198 #define buffer_write(b, v) (b = v)
199 #define RUN_ADDING 0
200 #define RUN_REPLACING 1
201
runSc4m(LADSPA_Handle instance,unsigned long sample_count)202 static void runSc4m(LADSPA_Handle instance, unsigned long sample_count) {
203 Sc4m *plugin_data = (Sc4m *)instance;
204
205 /* RMS/peak (float value) */
206 const LADSPA_Data rms_peak = *(plugin_data->rms_peak);
207
208 /* Attack time (ms) (float value) */
209 const LADSPA_Data attack = *(plugin_data->attack);
210
211 /* Release time (ms) (float value) */
212 const LADSPA_Data release = *(plugin_data->release);
213
214 /* Threshold level (dB) (float value) */
215 const LADSPA_Data threshold = *(plugin_data->threshold);
216
217 /* Ratio (1:n) (float value) */
218 const LADSPA_Data ratio = *(plugin_data->ratio);
219
220 /* Knee radius (dB) (float value) */
221 const LADSPA_Data knee = *(plugin_data->knee);
222
223 /* Makeup gain (dB) (float value) */
224 const LADSPA_Data makeup_gain = *(plugin_data->makeup_gain);
225
226 /* Input (array of floats of length sample_count) */
227 const LADSPA_Data * const input = plugin_data->input;
228
229 /* Output (array of floats of length sample_count) */
230 LADSPA_Data * const output = plugin_data->output;
231 float amp = plugin_data->amp;
232 float * as = plugin_data->as;
233 unsigned int count = plugin_data->count;
234 float env = plugin_data->env;
235 float env_peak = plugin_data->env_peak;
236 float env_rms = plugin_data->env_rms;
237 float gain = plugin_data->gain;
238 float gain_t = plugin_data->gain_t;
239 rms_env * rms = plugin_data->rms;
240 float sum = plugin_data->sum;
241
242 #line 51 "sc4m_1916.xml"
243 unsigned long pos;
244
245 const float ga = attack < 2.0f ? 0.0f : as[f_round(attack * 0.001f * (float)(A_TBL-1))];
246 const float gr = as[f_round(release * 0.001f * (float)(A_TBL-1))];
247 const float rs = (ratio - 1.0f) / ratio;
248 const float mug = db2lin(makeup_gain);
249 const float knee_min = db2lin(threshold - knee);
250 const float knee_max = db2lin(threshold + knee);
251 const float ef_a = ga * 0.25f;
252 const float ef_ai = 1.0f - ef_a;
253
254 for (pos = 0; pos < sample_count; pos++) {
255 const float lev_in = input[pos];
256 sum += lev_in * lev_in;
257
258 if (amp > env_rms) {
259 env_rms = env_rms * ga + amp * (1.0f - ga);
260 } else {
261 env_rms = env_rms * gr + amp * (1.0f - gr);
262 }
263 round_to_zero(&env_rms);
264 if (lev_in > env_peak) {
265 env_peak = env_peak * ga + lev_in * (1.0f - ga);
266 } else {
267 env_peak = env_peak * gr + lev_in * (1.0f - gr);
268 }
269 round_to_zero(&env_peak);
270 if ((count++ & 3) == 3) {
271 amp = rms_env_process(rms, sum * 0.25f);
272 sum = 0.0f;
273
274 env = LIN_INTERP(rms_peak, env_rms, env_peak);
275
276 if (env <= knee_min) {
277 gain_t = 1.0f;
278 } else if (env < knee_max) {
279 const float x = -(threshold - knee - lin2db(env)) / knee;
280 gain_t = db2lin(-knee * rs * x * x * 0.25f);
281 } else {
282 gain_t = db2lin((threshold - lin2db(env)) * rs);
283 }
284 }
285 gain = gain * ef_a + gain_t * ef_ai;
286 buffer_write(output[pos], input[pos] * gain * mug);
287 }
288 plugin_data->sum = sum;
289 plugin_data->amp = amp;
290 plugin_data->gain = gain;
291 plugin_data->gain_t = gain_t;
292 plugin_data->env = env;
293 plugin_data->env_rms = env_rms;
294 plugin_data->env_peak = env_peak;
295 plugin_data->count = count;
296
297 *(plugin_data->amplitude) = lin2db(env);
298 *(plugin_data->gain_red) = lin2db(gain);
299 }
300 #undef buffer_write
301 #undef RUN_ADDING
302 #undef RUN_REPLACING
303
304 #define buffer_write(b, v) (b += (v) * run_adding_gain)
305 #define RUN_ADDING 1
306 #define RUN_REPLACING 0
307
setRunAddingGainSc4m(LADSPA_Handle instance,LADSPA_Data gain)308 static void setRunAddingGainSc4m(LADSPA_Handle instance, LADSPA_Data gain) {
309 ((Sc4m *)instance)->run_adding_gain = gain;
310 }
311
runAddingSc4m(LADSPA_Handle instance,unsigned long sample_count)312 static void runAddingSc4m(LADSPA_Handle instance, unsigned long sample_count) {
313 Sc4m *plugin_data = (Sc4m *)instance;
314 LADSPA_Data run_adding_gain = plugin_data->run_adding_gain;
315
316 /* RMS/peak (float value) */
317 const LADSPA_Data rms_peak = *(plugin_data->rms_peak);
318
319 /* Attack time (ms) (float value) */
320 const LADSPA_Data attack = *(plugin_data->attack);
321
322 /* Release time (ms) (float value) */
323 const LADSPA_Data release = *(plugin_data->release);
324
325 /* Threshold level (dB) (float value) */
326 const LADSPA_Data threshold = *(plugin_data->threshold);
327
328 /* Ratio (1:n) (float value) */
329 const LADSPA_Data ratio = *(plugin_data->ratio);
330
331 /* Knee radius (dB) (float value) */
332 const LADSPA_Data knee = *(plugin_data->knee);
333
334 /* Makeup gain (dB) (float value) */
335 const LADSPA_Data makeup_gain = *(plugin_data->makeup_gain);
336
337 /* Input (array of floats of length sample_count) */
338 const LADSPA_Data * const input = plugin_data->input;
339
340 /* Output (array of floats of length sample_count) */
341 LADSPA_Data * const output = plugin_data->output;
342 float amp = plugin_data->amp;
343 float * as = plugin_data->as;
344 unsigned int count = plugin_data->count;
345 float env = plugin_data->env;
346 float env_peak = plugin_data->env_peak;
347 float env_rms = plugin_data->env_rms;
348 float gain = plugin_data->gain;
349 float gain_t = plugin_data->gain_t;
350 rms_env * rms = plugin_data->rms;
351 float sum = plugin_data->sum;
352
353 #line 51 "sc4m_1916.xml"
354 unsigned long pos;
355
356 const float ga = attack < 2.0f ? 0.0f : as[f_round(attack * 0.001f * (float)(A_TBL-1))];
357 const float gr = as[f_round(release * 0.001f * (float)(A_TBL-1))];
358 const float rs = (ratio - 1.0f) / ratio;
359 const float mug = db2lin(makeup_gain);
360 const float knee_min = db2lin(threshold - knee);
361 const float knee_max = db2lin(threshold + knee);
362 const float ef_a = ga * 0.25f;
363 const float ef_ai = 1.0f - ef_a;
364
365 for (pos = 0; pos < sample_count; pos++) {
366 const float lev_in = input[pos];
367 sum += lev_in * lev_in;
368
369 if (amp > env_rms) {
370 env_rms = env_rms * ga + amp * (1.0f - ga);
371 } else {
372 env_rms = env_rms * gr + amp * (1.0f - gr);
373 }
374 round_to_zero(&env_rms);
375 if (lev_in > env_peak) {
376 env_peak = env_peak * ga + lev_in * (1.0f - ga);
377 } else {
378 env_peak = env_peak * gr + lev_in * (1.0f - gr);
379 }
380 round_to_zero(&env_peak);
381 if ((count++ & 3) == 3) {
382 amp = rms_env_process(rms, sum * 0.25f);
383 sum = 0.0f;
384
385 env = LIN_INTERP(rms_peak, env_rms, env_peak);
386
387 if (env <= knee_min) {
388 gain_t = 1.0f;
389 } else if (env < knee_max) {
390 const float x = -(threshold - knee - lin2db(env)) / knee;
391 gain_t = db2lin(-knee * rs * x * x * 0.25f);
392 } else {
393 gain_t = db2lin((threshold - lin2db(env)) * rs);
394 }
395 }
396 gain = gain * ef_a + gain_t * ef_ai;
397 buffer_write(output[pos], input[pos] * gain * mug);
398 }
399 plugin_data->sum = sum;
400 plugin_data->amp = amp;
401 plugin_data->gain = gain;
402 plugin_data->gain_t = gain_t;
403 plugin_data->env = env;
404 plugin_data->env_rms = env_rms;
405 plugin_data->env_peak = env_peak;
406 plugin_data->count = count;
407
408 *(plugin_data->amplitude) = lin2db(env);
409 *(plugin_data->gain_red) = lin2db(gain);
410 }
411
swh_init()412 static void __attribute__((constructor)) swh_init() {
413 char **port_names;
414 LADSPA_PortDescriptor *port_descriptors;
415 LADSPA_PortRangeHint *port_range_hints;
416
417 #ifdef ENABLE_NLS
418 #define D_(s) dgettext(PACKAGE, s)
419 bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
420 #else
421 #define D_(s) (s)
422 #endif
423
424
425 sc4mDescriptor =
426 (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor));
427
428 if (sc4mDescriptor) {
429 sc4mDescriptor->UniqueID = 1916;
430 sc4mDescriptor->Label = "sc4m";
431 sc4mDescriptor->Properties =
432 LADSPA_PROPERTY_HARD_RT_CAPABLE;
433 sc4mDescriptor->Name =
434 D_("SC4 mono");
435 sc4mDescriptor->Maker =
436 "Steve Harris <steve@plugin.org.uk>";
437 sc4mDescriptor->Copyright =
438 "GPL";
439 sc4mDescriptor->PortCount = 11;
440
441 port_descriptors = (LADSPA_PortDescriptor *)calloc(11,
442 sizeof(LADSPA_PortDescriptor));
443 sc4mDescriptor->PortDescriptors =
444 (const LADSPA_PortDescriptor *)port_descriptors;
445
446 port_range_hints = (LADSPA_PortRangeHint *)calloc(11,
447 sizeof(LADSPA_PortRangeHint));
448 sc4mDescriptor->PortRangeHints =
449 (const LADSPA_PortRangeHint *)port_range_hints;
450
451 port_names = (char **)calloc(11, sizeof(char*));
452 sc4mDescriptor->PortNames =
453 (const char **)port_names;
454
455 /* Parameters for RMS/peak */
456 port_descriptors[SC4M_RMS_PEAK] =
457 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
458 port_names[SC4M_RMS_PEAK] =
459 D_("RMS/peak");
460 port_range_hints[SC4M_RMS_PEAK].HintDescriptor =
461 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MINIMUM;
462 port_range_hints[SC4M_RMS_PEAK].LowerBound = 0;
463 port_range_hints[SC4M_RMS_PEAK].UpperBound = 1;
464
465 /* Parameters for Attack time (ms) */
466 port_descriptors[SC4M_ATTACK] =
467 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
468 port_names[SC4M_ATTACK] =
469 D_("Attack time (ms)");
470 port_range_hints[SC4M_ATTACK].HintDescriptor =
471 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW;
472 port_range_hints[SC4M_ATTACK].LowerBound = 1.5;
473 port_range_hints[SC4M_ATTACK].UpperBound = 400;
474
475 /* Parameters for Release time (ms) */
476 port_descriptors[SC4M_RELEASE] =
477 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
478 port_names[SC4M_RELEASE] =
479 D_("Release time (ms)");
480 port_range_hints[SC4M_RELEASE].HintDescriptor =
481 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MIDDLE;
482 port_range_hints[SC4M_RELEASE].LowerBound = 2;
483 port_range_hints[SC4M_RELEASE].UpperBound = 800;
484
485 /* Parameters for Threshold level (dB) */
486 port_descriptors[SC4M_THRESHOLD] =
487 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
488 port_names[SC4M_THRESHOLD] =
489 D_("Threshold level (dB)");
490 port_range_hints[SC4M_THRESHOLD].HintDescriptor =
491 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_MAXIMUM;
492 port_range_hints[SC4M_THRESHOLD].LowerBound = -30;
493 port_range_hints[SC4M_THRESHOLD].UpperBound = 0;
494
495 /* Parameters for Ratio (1:n) */
496 port_descriptors[SC4M_RATIO] =
497 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
498 port_names[SC4M_RATIO] =
499 D_("Ratio (1:n)");
500 port_range_hints[SC4M_RATIO].HintDescriptor =
501 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_1;
502 port_range_hints[SC4M_RATIO].LowerBound = 1;
503 port_range_hints[SC4M_RATIO].UpperBound = 20;
504
505 /* Parameters for Knee radius (dB) */
506 port_descriptors[SC4M_KNEE] =
507 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
508 port_names[SC4M_KNEE] =
509 D_("Knee radius (dB)");
510 port_range_hints[SC4M_KNEE].HintDescriptor =
511 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_LOW;
512 port_range_hints[SC4M_KNEE].LowerBound = 1;
513 port_range_hints[SC4M_KNEE].UpperBound = 10;
514
515 /* Parameters for Makeup gain (dB) */
516 port_descriptors[SC4M_MAKEUP_GAIN] =
517 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
518 port_names[SC4M_MAKEUP_GAIN] =
519 D_("Makeup gain (dB)");
520 port_range_hints[SC4M_MAKEUP_GAIN].HintDescriptor =
521 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_DEFAULT_0;
522 port_range_hints[SC4M_MAKEUP_GAIN].LowerBound = 0;
523 port_range_hints[SC4M_MAKEUP_GAIN].UpperBound = +24;
524
525 /* Parameters for Amplitude (dB) */
526 port_descriptors[SC4M_AMPLITUDE] =
527 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
528 port_names[SC4M_AMPLITUDE] =
529 D_("Amplitude (dB)");
530 port_range_hints[SC4M_AMPLITUDE].HintDescriptor =
531 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
532 port_range_hints[SC4M_AMPLITUDE].LowerBound = -40;
533 port_range_hints[SC4M_AMPLITUDE].UpperBound = +12;
534
535 /* Parameters for Gain reduction (dB) */
536 port_descriptors[SC4M_GAIN_RED] =
537 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
538 port_names[SC4M_GAIN_RED] =
539 D_("Gain reduction (dB)");
540 port_range_hints[SC4M_GAIN_RED].HintDescriptor =
541 LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE;
542 port_range_hints[SC4M_GAIN_RED].LowerBound = -24;
543 port_range_hints[SC4M_GAIN_RED].UpperBound = 0;
544
545 /* Parameters for Input */
546 port_descriptors[SC4M_INPUT] =
547 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
548 port_names[SC4M_INPUT] =
549 D_("Input");
550 port_range_hints[SC4M_INPUT].HintDescriptor = 0;
551
552 /* Parameters for Output */
553 port_descriptors[SC4M_OUTPUT] =
554 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
555 port_names[SC4M_OUTPUT] =
556 D_("Output");
557 port_range_hints[SC4M_OUTPUT].HintDescriptor = 0;
558
559 sc4mDescriptor->activate = NULL;
560 sc4mDescriptor->cleanup = cleanupSc4m;
561 sc4mDescriptor->connect_port = connectPortSc4m;
562 sc4mDescriptor->deactivate = NULL;
563 sc4mDescriptor->instantiate = instantiateSc4m;
564 sc4mDescriptor->run = runSc4m;
565 sc4mDescriptor->run_adding = runAddingSc4m;
566 sc4mDescriptor->set_run_adding_gain = setRunAddingGainSc4m;
567 }
568 }
569
swh_fini()570 static void __attribute__((destructor)) swh_fini() {
571 if (sc4mDescriptor) {
572 free((LADSPA_PortDescriptor *)sc4mDescriptor->PortDescriptors);
573 free((char **)sc4mDescriptor->PortNames);
574 free((LADSPA_PortRangeHint *)sc4mDescriptor->PortRangeHints);
575 free(sc4mDescriptor);
576 }
577 sc4mDescriptor = NULL;
578
579 }
580