DistrhoPluginLADSPA+DSSI.cpp (24555B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any purpose with 6 * or without fee is hereby granted, provided that the above copyright notice and this 7 * permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN 11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "DistrhoPluginInternal.hpp" 18 19 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 20 # error Cannot use parameter value change request with LADSPA or DSSI 21 #endif 22 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 23 # error Cannot use MIDI Output with LADSPA or DSSI 24 #endif 25 #if DISTRHO_PLUGIN_WANT_FULL_STATE && !defined(DISTRHO_PLUGIN_WANT_FULL_STATE_WITH_LADSPA) 26 # error Cannot use full state with LADSPA or DSSI 27 #endif 28 29 #if DISTRHO_PLUGIN_WANT_TIMEPOS && !defined(DISTRHO_NO_WARNINGS) 30 # warning LADSPA/DSSI does not support TimePos 31 #endif 32 33 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 34 # include "dssi/dssi.h" 35 #else 36 # include "ladspa/ladspa.h" 37 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT 38 # error Cannot use MIDI with LADSPA 39 # endif 40 # if DISTRHO_PLUGIN_WANT_STATE && !defined(DISTRHO_NO_WARNINGS) 41 # warning LADSPA cannot handle states 42 # endif 43 #endif 44 45 START_NAMESPACE_DISTRHO 46 47 // ----------------------------------------------------------------------- 48 49 class PluginLadspaDssi 50 { 51 public: 52 PluginLadspaDssi() 53 : fPlugin(nullptr, nullptr, nullptr, nullptr), 54 fPortControls(nullptr), 55 fLastControlValues(nullptr) 56 { 57 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 58 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) 59 fPortAudioIns[i] = nullptr; 60 #else 61 fPortAudioIns = nullptr; 62 #endif 63 64 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 65 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) 66 fPortAudioOuts[i] = nullptr; 67 #else 68 fPortAudioOuts = nullptr; 69 #endif 70 71 if (const uint32_t count = fPlugin.getParameterCount()) 72 { 73 fPortControls = new LADSPA_Data*[count]; 74 fLastControlValues = new LADSPA_Data[count]; 75 76 for (uint32_t i=0; i < count; ++i) 77 { 78 fPortControls[i] = nullptr; 79 fLastControlValues[i] = fPlugin.getParameterValue(i); 80 } 81 } 82 else 83 { 84 fPortControls = nullptr; 85 fLastControlValues = nullptr; 86 } 87 88 #if DISTRHO_PLUGIN_WANT_LATENCY 89 fPortLatency = nullptr; 90 #endif 91 } 92 93 ~PluginLadspaDssi() noexcept 94 { 95 if (fPortControls != nullptr) 96 { 97 delete[] fPortControls; 98 fPortControls = nullptr; 99 } 100 101 if (fLastControlValues != nullptr) 102 { 103 delete[] fLastControlValues; 104 fLastControlValues = nullptr; 105 } 106 } 107 108 // ------------------------------------------------------------------- 109 110 void ladspa_activate() 111 { 112 fPlugin.activate(); 113 } 114 115 void ladspa_deactivate() 116 { 117 fPlugin.deactivate(); 118 } 119 120 // ------------------------------------------------------------------- 121 122 void ladspa_connect_port(const ulong port, LADSPA_Data* const dataLocation) noexcept 123 { 124 ulong index = 0; 125 126 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 127 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) 128 { 129 if (port == index++) 130 { 131 fPortAudioIns[i] = dataLocation; 132 return; 133 } 134 } 135 #endif 136 137 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 138 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) 139 { 140 if (port == index++) 141 { 142 fPortAudioOuts[i] = dataLocation; 143 return; 144 } 145 } 146 #endif 147 148 #if DISTRHO_PLUGIN_WANT_LATENCY 149 if (port == index++) 150 { 151 fPortLatency = dataLocation; 152 return; 153 } 154 #endif 155 156 for (ulong i=0, count=fPlugin.getParameterCount(); i < count; ++i) 157 { 158 if (port == index++) 159 { 160 fPortControls[i] = dataLocation; 161 return; 162 } 163 } 164 } 165 166 // ------------------------------------------------------------------- 167 168 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 169 void ladspa_run(const ulong sampleCount) 170 { 171 dssi_run_synth(sampleCount, nullptr, 0); 172 } 173 174 void dssi_run_synth(const ulong sampleCount, snd_seq_event_t* const events, const ulong eventCount) 175 #else 176 void ladspa_run(const ulong sampleCount) 177 #endif 178 { 179 // pre-roll 180 if (sampleCount == 0) 181 return updateParameterOutputsAndTriggers(); 182 183 // Check for updated parameters 184 float curValue; 185 186 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 187 { 188 if (fPortControls[i] == nullptr) 189 continue; 190 191 curValue = *fPortControls[i]; 192 193 if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue)) 194 { 195 fLastControlValues[i] = curValue; 196 fPlugin.setParameterValue(i, curValue); 197 } 198 } 199 200 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT 201 // Get MIDI Events 202 uint32_t midiEventCount = 0; 203 MidiEvent midiEvents[eventCount]; 204 205 for (uint32_t i=0, j; i < eventCount; ++i) 206 { 207 const snd_seq_event_t& seqEvent(events[i]); 208 209 // FIXME 210 if (seqEvent.data.note.channel > 0xF || seqEvent.data.control.channel > 0xF) 211 continue; 212 213 switch (seqEvent.type) 214 { 215 case SND_SEQ_EVENT_NOTEOFF: 216 j = midiEventCount++; 217 midiEvents[j].frame = seqEvent.time.tick; 218 midiEvents[j].size = 3; 219 midiEvents[j].data[0] = 0x80 + seqEvent.data.note.channel; 220 midiEvents[j].data[1] = seqEvent.data.note.note; 221 midiEvents[j].data[2] = 0; 222 midiEvents[j].data[3] = 0; 223 break; 224 case SND_SEQ_EVENT_NOTEON: 225 j = midiEventCount++; 226 midiEvents[j].frame = seqEvent.time.tick; 227 midiEvents[j].size = 3; 228 midiEvents[j].data[0] = 0x90 + seqEvent.data.note.channel; 229 midiEvents[j].data[1] = seqEvent.data.note.note; 230 midiEvents[j].data[2] = seqEvent.data.note.velocity; 231 midiEvents[j].data[3] = 0; 232 break; 233 case SND_SEQ_EVENT_KEYPRESS: 234 j = midiEventCount++; 235 midiEvents[j].frame = seqEvent.time.tick; 236 midiEvents[j].size = 3; 237 midiEvents[j].data[0] = 0xA0 + seqEvent.data.note.channel; 238 midiEvents[j].data[1] = seqEvent.data.note.note; 239 midiEvents[j].data[2] = seqEvent.data.note.velocity; 240 midiEvents[j].data[3] = 0; 241 break; 242 case SND_SEQ_EVENT_CONTROLLER: 243 j = midiEventCount++; 244 midiEvents[j].frame = seqEvent.time.tick; 245 midiEvents[j].size = 3; 246 midiEvents[j].data[0] = 0xB0 + seqEvent.data.control.channel; 247 midiEvents[j].data[1] = seqEvent.data.control.param; 248 midiEvents[j].data[2] = seqEvent.data.control.value; 249 midiEvents[j].data[3] = 0; 250 break; 251 case SND_SEQ_EVENT_CHANPRESS: 252 j = midiEventCount++; 253 midiEvents[j].frame = seqEvent.time.tick; 254 midiEvents[j].size = 2; 255 midiEvents[j].data[0] = 0xD0 + seqEvent.data.control.channel; 256 midiEvents[j].data[1] = seqEvent.data.control.value; 257 midiEvents[j].data[2] = 0; 258 midiEvents[j].data[3] = 0; 259 break; 260 case SND_SEQ_EVENT_PITCHBEND: 261 j = midiEventCount++; 262 midiEvents[j].frame = seqEvent.time.tick; 263 midiEvents[j].size = 3; 264 midiEvents[j].data[0] = 0xE0 + seqEvent.data.control.channel; 265 uint16_t tempvalue = seqEvent.data.control.value + 8192; 266 midiEvents[j].data[1] = tempvalue & 0x7F; 267 midiEvents[j].data[2] = tempvalue >> 7; 268 midiEvents[j].data[3] = 0; 269 break; 270 } 271 } 272 273 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, midiEvents, midiEventCount); 274 #else 275 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); 276 #endif 277 278 updateParameterOutputsAndTriggers(); 279 280 #if defined(DISTRHO_PLUGIN_TARGET_DSSI) && ! DISTRHO_PLUGIN_WANT_MIDI_INPUT 281 return; // unused 282 (void)events; (void)eventCount; 283 #endif 284 } 285 286 // ------------------------------------------------------------------- 287 288 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 289 # if DISTRHO_PLUGIN_WANT_STATE 290 char* dssi_configure(const char* const key, const char* const value) 291 { 292 if (std::strncmp(key, DSSI_RESERVED_CONFIGURE_PREFIX, std::strlen(DSSI_RESERVED_CONFIGURE_PREFIX)) == 0) 293 return nullptr; 294 if (std::strncmp(key, DSSI_GLOBAL_CONFIGURE_PREFIX, std::strlen(DSSI_GLOBAL_CONFIGURE_PREFIX)) == 0) 295 return nullptr; 296 297 fPlugin.setState(key, value); 298 return nullptr; 299 } 300 # endif 301 302 # if DISTRHO_PLUGIN_WANT_PROGRAMS 303 const DSSI_Program_Descriptor* dssi_get_program(const ulong index) 304 { 305 if (index >= fPlugin.getProgramCount()) 306 return nullptr; 307 308 static DSSI_Program_Descriptor desc; 309 310 desc.Bank = index / 128; 311 desc.Program = index % 128; 312 desc.Name = fPlugin.getProgramName(index); 313 314 return &desc; 315 } 316 317 void dssi_select_program(const ulong bank, const ulong program) 318 { 319 const ulong realProgram(bank * 128 + program); 320 321 DISTRHO_SAFE_ASSERT_RETURN(realProgram < fPlugin.getProgramCount(),); 322 323 fPlugin.loadProgram(realProgram); 324 325 // Update control inputs 326 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 327 { 328 if (fPlugin.isParameterOutput(i)) 329 continue; 330 331 fLastControlValues[i] = fPlugin.getParameterValue(i); 332 333 if (fPortControls[i] != nullptr) 334 *fPortControls[i] = fLastControlValues[i]; 335 } 336 } 337 # endif 338 339 int dssi_get_midi_controller_for_port(const ulong port) noexcept 340 { 341 const uint32_t parameterOffset = fPlugin.getParameterOffset(); 342 343 if (port > parameterOffset) 344 return DSSI_NONE; 345 346 const uint8_t midiCC = fPlugin.getParameterMidiCC(port-parameterOffset); 347 348 if (midiCC == 0 || midiCC == 32 || midiCC >= 0x78) 349 return DSSI_NONE; 350 351 return DSSI_CC(midiCC); 352 } 353 #endif 354 355 // ------------------------------------------------------------------- 356 357 private: 358 PluginExporter fPlugin; 359 360 // LADSPA ports 361 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 362 const LADSPA_Data* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; 363 #else 364 const LADSPA_Data** fPortAudioIns; 365 #endif 366 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 367 LADSPA_Data* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; 368 #else 369 LADSPA_Data** fPortAudioOuts; 370 #endif 371 LADSPA_Data** fPortControls; 372 #if DISTRHO_PLUGIN_WANT_LATENCY 373 LADSPA_Data* fPortLatency; 374 #endif 375 376 // Temporary data 377 LADSPA_Data* fLastControlValues; 378 379 // ------------------------------------------------------------------- 380 381 void updateParameterOutputsAndTriggers() 382 { 383 float value; 384 385 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 386 { 387 if (fPlugin.isParameterOutput(i)) 388 { 389 value = fLastControlValues[i] = fPlugin.getParameterValue(i); 390 391 if (fPortControls[i] != nullptr) 392 *fPortControls[i] = value; 393 } 394 else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) 395 { 396 // NOTE: no trigger support in LADSPA control ports, simulate it here 397 value = fPlugin.getParameterRanges(i).def; 398 399 if (d_isEqual(value, fPlugin.getParameterValue(i))) 400 continue; 401 402 fLastControlValues[i] = value; 403 fPlugin.setParameterValue(i, value); 404 405 if (fPortControls[i] != nullptr) 406 *fPortControls[i] = value; 407 } 408 } 409 410 #if DISTRHO_PLUGIN_WANT_LATENCY 411 if (fPortLatency != nullptr) 412 *fPortLatency = fPlugin.getLatency(); 413 #endif 414 } 415 }; 416 417 // ----------------------------------------------------------------------- 418 419 static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, ulong sampleRate) 420 { 421 if (d_nextBufferSize == 0) 422 d_nextBufferSize = 2048; 423 d_nextSampleRate = sampleRate; 424 425 return new PluginLadspaDssi(); 426 } 427 428 #define instancePtr ((PluginLadspaDssi*)instance) 429 430 static void ladspa_connect_port(LADSPA_Handle instance, ulong port, LADSPA_Data* dataLocation) 431 { 432 instancePtr->ladspa_connect_port(port, dataLocation); 433 } 434 435 static void ladspa_activate(LADSPA_Handle instance) 436 { 437 instancePtr->ladspa_activate(); 438 } 439 440 static void ladspa_run(LADSPA_Handle instance, ulong sampleCount) 441 { 442 instancePtr->ladspa_run(sampleCount); 443 } 444 445 static void ladspa_deactivate(LADSPA_Handle instance) 446 { 447 instancePtr->ladspa_deactivate(); 448 } 449 450 static void ladspa_cleanup(LADSPA_Handle instance) 451 { 452 delete instancePtr; 453 } 454 455 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 456 # if DISTRHO_PLUGIN_WANT_STATE 457 static char* dssi_configure(LADSPA_Handle instance, const char* key, const char* value) 458 { 459 return instancePtr->dssi_configure(key, value); 460 } 461 # endif 462 463 # if DISTRHO_PLUGIN_WANT_PROGRAMS 464 static const DSSI_Program_Descriptor* dssi_get_program(LADSPA_Handle instance, ulong index) 465 { 466 return instancePtr->dssi_get_program(index); 467 } 468 469 static void dssi_select_program(LADSPA_Handle instance, ulong bank, ulong program) 470 { 471 instancePtr->dssi_select_program(bank, program); 472 } 473 # endif 474 475 static int dssi_get_midi_controller_for_port(LADSPA_Handle instance, ulong port) 476 { 477 return instancePtr->dssi_get_midi_controller_for_port(port); 478 } 479 480 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT 481 static void dssi_run_synth(LADSPA_Handle instance, ulong sampleCount, snd_seq_event_t* events, ulong eventCount) 482 { 483 instancePtr->dssi_run_synth(sampleCount, events, eventCount); 484 } 485 # endif 486 #endif 487 488 #undef instancePtr 489 490 // ----------------------------------------------------------------------- 491 492 static LADSPA_Descriptor sLadspaDescriptor = { 493 /* UniqueID */ 0, 494 /* Label */ nullptr, 495 #if DISTRHO_PLUGIN_IS_RT_SAFE 496 /* Properties */ LADSPA_PROPERTY_HARD_RT_CAPABLE, 497 #else 498 /* Properties */ 0x0, 499 #endif 500 /* Name */ nullptr, 501 /* Maker */ nullptr, 502 /* Copyright */ nullptr, 503 /* PortCount */ 0, 504 /* PortDescriptors */ nullptr, 505 /* PortNames */ nullptr, 506 /* PortRangeHints */ nullptr, 507 /* ImplementationData */ nullptr, 508 ladspa_instantiate, 509 ladspa_connect_port, 510 ladspa_activate, 511 ladspa_run, 512 /* run_adding */ nullptr, 513 /* set_run_adding_gain */ nullptr, 514 ladspa_deactivate, 515 ladspa_cleanup 516 }; 517 518 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 519 static DSSI_Descriptor sDssiDescriptor = { 520 1, 521 &sLadspaDescriptor, 522 # if DISTRHO_PLUGIN_WANT_STATE 523 dssi_configure, 524 # else 525 /* configure */ nullptr, 526 # endif 527 # if DISTRHO_PLUGIN_WANT_PROGRAMS 528 dssi_get_program, 529 dssi_select_program, 530 # else 531 /* get_program */ nullptr, 532 /* select_program */ nullptr, 533 # endif 534 dssi_get_midi_controller_for_port, 535 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT 536 dssi_run_synth, 537 # else 538 /* run_synth */ nullptr, 539 # endif 540 /* run_synth_adding */ nullptr, 541 /* run_multiple_synths */ nullptr, 542 /* run_multiple_synths_adding */ nullptr, 543 nullptr, nullptr 544 }; 545 #endif 546 547 // ----------------------------------------------------------------------- 548 549 static const struct DescriptorInitializer 550 { 551 DescriptorInitializer() 552 { 553 // Create dummy plugin to get data from 554 d_nextBufferSize = 512; 555 d_nextSampleRate = 44100.0; 556 d_nextPluginIsDummy = true; 557 const PluginExporter plugin(nullptr, nullptr, nullptr, nullptr); 558 d_nextBufferSize = 0; 559 d_nextSampleRate = 0.0; 560 d_nextPluginIsDummy = false; 561 562 // Get port count, init 563 ulong port = 0; 564 ulong portCount = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS + plugin.getParameterCount(); 565 #if DISTRHO_PLUGIN_WANT_LATENCY 566 portCount += 1; 567 #endif 568 const char** const portNames = new const char*[portCount]; 569 LADSPA_PortDescriptor* portDescriptors = new LADSPA_PortDescriptor[portCount]; 570 LADSPA_PortRangeHint* portRangeHints = new LADSPA_PortRangeHint [portCount]; 571 572 // Set ports 573 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 574 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++port) 575 { 576 const AudioPort& aport(plugin.getAudioPort(true, i)); 577 578 portNames[port] = strdup(aport.name); 579 portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT; 580 581 portRangeHints[port].HintDescriptor = 0x0; 582 portRangeHints[port].LowerBound = 0.0f; 583 portRangeHints[port].UpperBound = 1.0f; 584 } 585 #endif 586 587 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 588 for (ulong i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++port) 589 { 590 const AudioPort& aport(plugin.getAudioPort(false, i)); 591 592 portNames[port] = strdup(aport.name); 593 portDescriptors[port] = LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT; 594 595 portRangeHints[port].HintDescriptor = 0x0; 596 portRangeHints[port].LowerBound = 0.0f; 597 portRangeHints[port].UpperBound = 1.0f; 598 } 599 #endif 600 601 #if DISTRHO_PLUGIN_WANT_LATENCY 602 // Set latency port 603 portNames[port] = strdup("_latency"); 604 portDescriptors[port] = LADSPA_PORT_CONTROL | LADSPA_PORT_OUTPUT; 605 portRangeHints[port].HintDescriptor = LADSPA_HINT_SAMPLE_RATE|LADSPA_HINT_INTEGER; 606 portRangeHints[port].LowerBound = 0.0f; 607 portRangeHints[port].UpperBound = 1.0f; 608 ++port; 609 #endif 610 611 for (ulong i=0, count=plugin.getParameterCount(); i < count; ++i, ++port) 612 { 613 portNames[port] = strdup((const char*)plugin.getParameterName(i)); 614 portDescriptors[port] = LADSPA_PORT_CONTROL; 615 616 if (plugin.isParameterOutput(i)) 617 portDescriptors[port] |= LADSPA_PORT_OUTPUT; 618 else 619 portDescriptors[port] |= LADSPA_PORT_INPUT; 620 621 const uint32_t hints = plugin.getParameterHints(i); 622 623 { 624 const ParameterRanges& ranges(plugin.getParameterRanges(i)); 625 const float defValue = ranges.def; 626 627 // LADSPA doesn't allow bounded hints on toggles 628 portRangeHints[port].HintDescriptor = hints & kParameterIsBoolean 629 ? 0 630 : LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE; 631 632 portRangeHints[port].LowerBound = ranges.min; 633 portRangeHints[port].UpperBound = ranges.max; 634 635 /**/ if (d_isZero(defValue)) 636 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_0; 637 else if (d_isEqual(defValue, 1.0f)) 638 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_1; 639 else if (d_isEqual(defValue, 100.0f)) 640 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_100; 641 else if (d_isEqual(defValue, 440.0f)) 642 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_440; 643 else if (d_isEqual(ranges.min, defValue)) 644 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM; 645 else if (d_isEqual(ranges.max, defValue)) 646 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM; 647 else 648 { 649 const float middleValue = ranges.min/2.0f + ranges.max/2.0f; 650 const float middleLow = (ranges.min/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f; 651 const float middleHigh = (ranges.max/2.0f + middleValue/2.0f)/2.0f + middleValue/2.0f; 652 653 /**/ if (defValue < middleLow) 654 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_LOW; 655 else if (defValue > middleHigh) 656 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH; 657 else 658 portRangeHints[port].HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE; 659 } 660 } 661 662 { 663 if (hints & kParameterIsBoolean) 664 { 665 portRangeHints[port].HintDescriptor |= LADSPA_HINT_TOGGLED; 666 } 667 else 668 { 669 if (hints & kParameterIsInteger) 670 portRangeHints[port].HintDescriptor |= LADSPA_HINT_INTEGER; 671 if (hints & kParameterIsLogarithmic) 672 portRangeHints[port].HintDescriptor |= LADSPA_HINT_LOGARITHMIC; 673 } 674 } 675 } 676 677 // Set data 678 sLadspaDescriptor.UniqueID = plugin.getUniqueId(); 679 sLadspaDescriptor.Label = strdup(plugin.getLabel()); 680 sLadspaDescriptor.Name = strdup(plugin.getName()); 681 sLadspaDescriptor.Maker = strdup(plugin.getMaker()); 682 sLadspaDescriptor.Copyright = strdup(plugin.getLicense()); 683 sLadspaDescriptor.PortCount = portCount; 684 sLadspaDescriptor.PortNames = portNames; 685 sLadspaDescriptor.PortDescriptors = portDescriptors; 686 sLadspaDescriptor.PortRangeHints = portRangeHints; 687 } 688 689 ~DescriptorInitializer() 690 { 691 if (sLadspaDescriptor.Label != nullptr) 692 { 693 std::free((void*)sLadspaDescriptor.Label); 694 sLadspaDescriptor.Label = nullptr; 695 } 696 697 if (sLadspaDescriptor.Name != nullptr) 698 { 699 std::free((void*)sLadspaDescriptor.Name); 700 sLadspaDescriptor.Name = nullptr; 701 } 702 703 if (sLadspaDescriptor.Maker != nullptr) 704 { 705 std::free((void*)sLadspaDescriptor.Maker); 706 sLadspaDescriptor.Maker = nullptr; 707 } 708 709 if (sLadspaDescriptor.Copyright != nullptr) 710 { 711 std::free((void*)sLadspaDescriptor.Copyright); 712 sLadspaDescriptor.Copyright = nullptr; 713 } 714 715 if (sLadspaDescriptor.PortDescriptors != nullptr) 716 { 717 delete[] sLadspaDescriptor.PortDescriptors; 718 sLadspaDescriptor.PortDescriptors = nullptr; 719 } 720 721 if (sLadspaDescriptor.PortRangeHints != nullptr) 722 { 723 delete[] sLadspaDescriptor.PortRangeHints; 724 sLadspaDescriptor.PortRangeHints = nullptr; 725 } 726 727 if (sLadspaDescriptor.PortNames != nullptr) 728 { 729 for (ulong i=0; i < sLadspaDescriptor.PortCount; ++i) 730 { 731 if (sLadspaDescriptor.PortNames[i] != nullptr) 732 std::free((void*)sLadspaDescriptor.PortNames[i]); 733 } 734 735 delete[] sLadspaDescriptor.PortNames; 736 sLadspaDescriptor.PortNames = nullptr; 737 } 738 } 739 } sDescInit; 740 741 // ----------------------------------------------------------------------- 742 743 END_NAMESPACE_DISTRHO 744 745 DISTRHO_PLUGIN_EXPORT 746 const LADSPA_Descriptor* ladspa_descriptor(ulong index) 747 { 748 USE_NAMESPACE_DISTRHO 749 return (index == 0) ? &sLadspaDescriptor : nullptr; 750 } 751 752 #ifdef DISTRHO_PLUGIN_TARGET_DSSI 753 DISTRHO_PLUGIN_EXPORT 754 const DSSI_Descriptor* dssi_descriptor(ulong index) 755 { 756 USE_NAMESPACE_DISTRHO 757 return (index == 0) ? &sDssiDescriptor : nullptr; 758 } 759 #endif 760 761 // -----------------------------------------------------------------------