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