1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2020 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 #include "lv2/atom.h" 20 #include "lv2/atom-util.h" 21 #include "lv2/buf-size.h" 22 #include "lv2/data-access.h" 23 #include "lv2/instance-access.h" 24 #include "lv2/midi.h" 25 #include "lv2/options.h" 26 #include "lv2/parameters.h" 27 #include "lv2/patch.h" 28 #include "lv2/state.h" 29 #include "lv2/time.h" 30 #include "lv2/urid.h" 31 #include "lv2/worker.h" 32 #include "lv2/lv2_kxstudio_properties.h" 33 #include "lv2/lv2_programs.h" 34 35 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 36 # include "libmodla.h" 37 #endif 38 39 #ifdef noexcept 40 # undef noexcept 41 #endif 42 43 #include <map> 44 45 #ifndef DISTRHO_PLUGIN_URI 46 # error DISTRHO_PLUGIN_URI undefined! 47 #endif 48 49 #ifndef DISTRHO_PLUGIN_LV2_STATE_PREFIX 50 # define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:" 51 #endif 52 53 #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) 54 #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) 55 56 START_NAMESPACE_DISTRHO 57 58 typedef std::map<const String, String> StringToStringMap; 59 typedef std::map<const LV2_URID, String> UridToStringMap; 60 61 #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 62 static const writeMidiFunc writeMidiCallback = nullptr; 63 #endif 64 65 // ----------------------------------------------------------------------- 66 67 class PluginLv2 68 { 69 public: 70 PluginLv2(const double sampleRate, 71 const LV2_URID_Map* const uridMap, 72 const LV2_Worker_Schedule* const worker, 73 const bool usingNominal) 74 : fPlugin(this, writeMidiCallback), 75 fUsingNominal(usingNominal), 76 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 77 fRunCount(0), 78 #endif 79 fPortControls(nullptr), 80 fLastControlValues(nullptr), 81 fSampleRate(sampleRate), 82 fURIDs(uridMap), 83 fUridMap(uridMap), 84 fWorker(worker) 85 { 86 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 87 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) 88 fPortAudioIns[i] = nullptr; 89 #else 90 fPortAudioIns = nullptr; 91 #endif 92 93 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 94 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) 95 fPortAudioOuts[i] = nullptr; 96 #else 97 fPortAudioOuts = nullptr; 98 #endif 99 100 if (const uint32_t count = fPlugin.getParameterCount()) 101 { 102 fPortControls = new float*[count]; 103 fLastControlValues = new float[count]; 104 105 for (uint32_t i=0; i < count; ++i) 106 { 107 fPortControls[i] = nullptr; 108 fLastControlValues[i] = fPlugin.getParameterValue(i); 109 } 110 } 111 else 112 { 113 fPortControls = nullptr; 114 fLastControlValues = nullptr; 115 } 116 117 #if DISTRHO_LV2_USE_EVENTS_IN 118 fPortEventsIn = nullptr; 119 #endif 120 #if DISTRHO_PLUGIN_WANT_LATENCY 121 fPortLatency = nullptr; 122 #endif 123 124 #if DISTRHO_PLUGIN_WANT_STATE 125 if (const uint32_t count = fPlugin.getStateCount()) 126 { 127 fNeededUiSends = new bool[count]; 128 129 for (uint32_t i=0; i < count; ++i) 130 { 131 fNeededUiSends[i] = false; 132 133 const String& dkey(fPlugin.getStateKey(i)); 134 fStateMap[dkey] = fPlugin.getStateDefaultValue(i); 135 136 # if DISTRHO_PLUGIN_WANT_STATEFILES 137 if (fPlugin.isStateFile(i)) 138 { 139 const String dpf_lv2_key(DISTRHO_PLUGIN_URI "#" + dkey); 140 const LV2_URID urid = uridMap->map(uridMap->handle, dpf_lv2_key.buffer()); 141 fUridStateFileMap[urid] = dkey; 142 } 143 # endif 144 } 145 } 146 else 147 { 148 fNeededUiSends = nullptr; 149 } 150 #else 151 // unused 152 (void)fWorker; 153 #endif 154 } 155 156 ~PluginLv2() 157 { 158 if (fPortControls != nullptr) 159 { 160 delete[] fPortControls; 161 fPortControls = nullptr; 162 } 163 164 if (fLastControlValues) 165 { 166 delete[] fLastControlValues; 167 fLastControlValues = nullptr; 168 } 169 170 #if DISTRHO_PLUGIN_WANT_STATE 171 if (fNeededUiSends != nullptr) 172 { 173 delete[] fNeededUiSends; 174 fNeededUiSends = nullptr; 175 } 176 177 fStateMap.clear(); 178 #endif 179 } 180 181 // ------------------------------------------------------------------- 182 183 bool getPortControlValue(uint32_t index, float& value) const 184 { 185 if (const float* control = fPortControls[index]) 186 { 187 switch (fPlugin.getParameterDesignation(index)) 188 { 189 default: 190 value = *control; 191 break; 192 case kParameterDesignationBypass: 193 value = 1.0f - *control; 194 break; 195 } 196 197 return true; 198 } 199 200 return false; 201 } 202 203 void setPortControlValue(uint32_t index, float value) 204 { 205 if (float* control = fPortControls[index]) 206 { 207 switch (fPlugin.getParameterDesignation(index)) 208 { 209 default: 210 *control = value; 211 break; 212 case kParameterDesignationBypass: 213 *control = 1.0f - value; 214 break; 215 } 216 } 217 } 218 219 // ------------------------------------------------------------------- 220 221 void lv2_activate() 222 { 223 #if DISTRHO_PLUGIN_WANT_TIMEPOS 224 fTimePosition.clear(); 225 226 // hosts may not send all values, resulting on some invalid data 227 fTimePosition.bbt.bar = 1; 228 fTimePosition.bbt.beat = 1; 229 fTimePosition.bbt.tick = 0; 230 fTimePosition.bbt.barStartTick = 0; 231 fTimePosition.bbt.beatsPerBar = 4; 232 fTimePosition.bbt.beatType = 4; 233 fTimePosition.bbt.ticksPerBeat = 960.0; 234 fTimePosition.bbt.beatsPerMinute = 120.0; 235 #endif 236 fPlugin.activate(); 237 } 238 239 void lv2_deactivate() 240 { 241 fPlugin.deactivate(); 242 } 243 244 // ------------------------------------------------------------------- 245 246 void lv2_connect_port(const uint32_t port, void* const dataLocation) 247 { 248 uint32_t index = 0; 249 250 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 251 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) 252 { 253 if (port == index++) 254 { 255 fPortAudioIns[i] = (const float*)dataLocation; 256 return; 257 } 258 } 259 #endif 260 261 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 262 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) 263 { 264 if (port == index++) 265 { 266 fPortAudioOuts[i] = (float*)dataLocation; 267 return; 268 } 269 } 270 #endif 271 272 #if DISTRHO_LV2_USE_EVENTS_IN 273 if (port == index++) 274 { 275 fPortEventsIn = (LV2_Atom_Sequence*)dataLocation; 276 return; 277 } 278 #endif 279 280 #if DISTRHO_LV2_USE_EVENTS_OUT 281 if (port == index++) 282 { 283 fEventsOutData.port = (LV2_Atom_Sequence*)dataLocation; 284 return; 285 } 286 #endif 287 288 #if DISTRHO_PLUGIN_WANT_LATENCY 289 if (port == index++) 290 { 291 fPortLatency = (float*)dataLocation; 292 return; 293 } 294 #endif 295 296 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 297 { 298 if (port == index++) 299 { 300 fPortControls[i] = (float*)dataLocation; 301 return; 302 } 303 } 304 } 305 306 // ------------------------------------------------------------------- 307 308 void lv2_run(const uint32_t sampleCount) 309 { 310 // cache midi input and time position first 311 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT 312 uint32_t midiEventCount = 0; 313 #endif 314 315 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS 316 LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) 317 { 318 if (event == nullptr) 319 break; 320 321 # if DISTRHO_PLUGIN_WANT_MIDI_INPUT 322 if (event->body.type == fURIDs.midiEvent) 323 { 324 if (midiEventCount >= kMaxMidiEvents) 325 continue; 326 327 const uint8_t* const data((const uint8_t*)(event + 1)); 328 329 MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); 330 331 midiEvent.frame = event->time.frames; 332 midiEvent.size = event->body.size; 333 334 if (midiEvent.size > MidiEvent::kDataSize) 335 { 336 midiEvent.dataExt = data; 337 std::memset(midiEvent.data, 0, MidiEvent::kDataSize); 338 } 339 else 340 { 341 midiEvent.dataExt = nullptr; 342 std::memcpy(midiEvent.data, data, midiEvent.size); 343 } 344 345 continue; 346 } 347 # endif 348 # if DISTRHO_PLUGIN_WANT_TIMEPOS 349 if (event->body.type == fURIDs.atomBlank || event->body.type == fURIDs.atomObject) 350 { 351 const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body); 352 353 if (obj->body.otype != fURIDs.timePosition) 354 continue; 355 356 LV2_Atom* bar = nullptr; 357 LV2_Atom* barBeat = nullptr; 358 LV2_Atom* beatUnit = nullptr; 359 LV2_Atom* beatsPerBar = nullptr; 360 LV2_Atom* beatsPerMinute = nullptr; 361 LV2_Atom* frame = nullptr; 362 LV2_Atom* speed = nullptr; 363 LV2_Atom* ticksPerBeat = nullptr; 364 365 lv2_atom_object_get(obj, 366 fURIDs.timeBar, &bar, 367 fURIDs.timeBarBeat, &barBeat, 368 fURIDs.timeBeatUnit, &beatUnit, 369 fURIDs.timeBeatsPerBar, &beatsPerBar, 370 fURIDs.timeBeatsPerMinute, &beatsPerMinute, 371 fURIDs.timeFrame, &frame, 372 fURIDs.timeSpeed, &speed, 373 fURIDs.timeTicksPerBeat, &ticksPerBeat, 374 0); 375 376 // need to handle this first as other values depend on it 377 if (ticksPerBeat != nullptr) 378 { 379 /**/ if (ticksPerBeat->type == fURIDs.atomDouble) 380 fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; 381 else if (ticksPerBeat->type == fURIDs.atomFloat) 382 fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; 383 else if (ticksPerBeat->type == fURIDs.atomInt) 384 fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; 385 else if (ticksPerBeat->type == fURIDs.atomLong) 386 fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; 387 else 388 d_stderr("Unknown lv2 ticksPerBeat value type"); 389 390 if (fLastPositionData.ticksPerBeat > 0.0) 391 fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; 392 } 393 394 // same 395 if (speed != nullptr) 396 { 397 /**/ if (speed->type == fURIDs.atomDouble) 398 fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; 399 else if (speed->type == fURIDs.atomFloat) 400 fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; 401 else if (speed->type == fURIDs.atomInt) 402 fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; 403 else if (speed->type == fURIDs.atomLong) 404 fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; 405 else 406 d_stderr("Unknown lv2 speed value type"); 407 408 fTimePosition.playing = d_isNotZero(fLastPositionData.speed); 409 } 410 411 if (bar != nullptr) 412 { 413 /**/ if (bar->type == fURIDs.atomDouble) 414 fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; 415 else if (bar->type == fURIDs.atomFloat) 416 fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; 417 else if (bar->type == fURIDs.atomInt) 418 fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; 419 else if (bar->type == fURIDs.atomLong) 420 fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; 421 else 422 d_stderr("Unknown lv2 bar value type"); 423 424 if (fLastPositionData.bar >= 0) 425 fTimePosition.bbt.bar = fLastPositionData.bar + 1; 426 } 427 428 if (barBeat != nullptr) 429 { 430 /**/ if (barBeat->type == fURIDs.atomDouble) 431 fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; 432 else if (barBeat->type == fURIDs.atomFloat) 433 fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; 434 else if (barBeat->type == fURIDs.atomInt) 435 fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; 436 else if (barBeat->type == fURIDs.atomLong) 437 fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; 438 else 439 d_stderr("Unknown lv2 barBeat value type"); 440 441 if (fLastPositionData.barBeat >= 0.0f) 442 { 443 const double rest = std::fmod(fLastPositionData.barBeat, 1.0f); 444 fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat-rest+1.0); 445 fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; 446 } 447 } 448 449 if (beatUnit != nullptr) 450 { 451 /**/ if (beatUnit->type == fURIDs.atomDouble) 452 fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; 453 else if (beatUnit->type == fURIDs.atomFloat) 454 fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; 455 else if (beatUnit->type == fURIDs.atomInt) 456 fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; 457 else if (beatUnit->type == fURIDs.atomLong) 458 fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; 459 else 460 d_stderr("Unknown lv2 beatUnit value type"); 461 462 if (fLastPositionData.beatUnit > 0) 463 fTimePosition.bbt.beatType = fLastPositionData.beatUnit; 464 } 465 466 if (beatsPerBar != nullptr) 467 { 468 /**/ if (beatsPerBar->type == fURIDs.atomDouble) 469 fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; 470 else if (beatsPerBar->type == fURIDs.atomFloat) 471 fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; 472 else if (beatsPerBar->type == fURIDs.atomInt) 473 fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; 474 else if (beatsPerBar->type == fURIDs.atomLong) 475 fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; 476 else 477 d_stderr("Unknown lv2 beatsPerBar value type"); 478 479 if (fLastPositionData.beatsPerBar > 0.0f) 480 fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar; 481 } 482 483 if (beatsPerMinute != nullptr) 484 { 485 /**/ if (beatsPerMinute->type == fURIDs.atomDouble) 486 fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; 487 else if (beatsPerMinute->type == fURIDs.atomFloat) 488 fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; 489 else if (beatsPerMinute->type == fURIDs.atomInt) 490 fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; 491 else if (beatsPerMinute->type == fURIDs.atomLong) 492 fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; 493 else 494 d_stderr("Unknown lv2 beatsPerMinute value type"); 495 496 if (fLastPositionData.beatsPerMinute > 0.0f) 497 { 498 fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; 499 500 if (d_isNotZero(fLastPositionData.speed)) 501 fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); 502 } 503 } 504 505 if (frame != nullptr) 506 { 507 /**/ if (frame->type == fURIDs.atomDouble) 508 fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; 509 else if (frame->type == fURIDs.atomFloat) 510 fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; 511 else if (frame->type == fURIDs.atomInt) 512 fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; 513 else if (frame->type == fURIDs.atomLong) 514 fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; 515 else 516 d_stderr("Unknown lv2 frame value type"); 517 518 if (fLastPositionData.frame >= 0) 519 fTimePosition.frame = fLastPositionData.frame; 520 } 521 522 fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* 523 fTimePosition.bbt.beatsPerBar* 524 (fTimePosition.bbt.bar-1); 525 526 fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && 527 fLastPositionData.beatUnit > 0 && 528 fLastPositionData.beatsPerBar > 0.0f); 529 530 fPlugin.setTimePosition(fTimePosition); 531 532 continue; 533 } 534 # endif 535 } 536 #endif 537 538 // check for messages from UI or files 539 #if DISTRHO_PLUGIN_WANT_STATE && (DISTRHO_PLUGIN_HAS_UI || DISTRHO_PLUGIN_WANT_STATEFILES) 540 LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) 541 { 542 if (event == nullptr) 543 break; 544 545 if (event->body.type == fURIDs.dpfKeyValue) 546 { 547 const void* const data = (const void*)(event + 1); 548 549 // check if this is our special message 550 if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0) 551 { 552 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) 553 fNeededUiSends[i] = true; 554 } 555 // no, send to DSP as usual 556 else if (fWorker != nullptr) 557 { 558 fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); 559 } 560 } 561 # if DISTRHO_PLUGIN_WANT_STATEFILES 562 else if (event->body.type == fURIDs.atomObject && fWorker != nullptr) 563 { 564 const LV2_Atom_Object* const object = (const LV2_Atom_Object*)&event->body; 565 566 const LV2_Atom* property = nullptr; 567 const LV2_Atom* value = nullptr; 568 lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); 569 570 if (property != nullptr && property->type == fURIDs.atomURID && 571 value != nullptr && value->type == fURIDs.atomPath) 572 { 573 fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); 574 } 575 } 576 # endif 577 } 578 #endif 579 580 // Check for updated parameters 581 float curValue; 582 583 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 584 { 585 if (!getPortControlValue(i, curValue)) 586 continue; 587 588 if (fPlugin.isParameterInput(i) && d_isNotEqual(fLastControlValues[i], curValue)) 589 { 590 fLastControlValues[i] = curValue; 591 592 fPlugin.setParameterValue(i, curValue); 593 } 594 } 595 596 // Run plugin 597 if (sampleCount != 0) 598 { 599 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 600 fRunCount = mod_license_run_begin(fRunCount, sampleCount); 601 #endif 602 603 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT 604 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); 605 #else 606 fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); 607 #endif 608 609 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 610 for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) 611 mod_license_run_silence(fRunCount, fPortAudioOuts[i], sampleCount, i); 612 #endif 613 614 #if DISTRHO_PLUGIN_WANT_TIMEPOS 615 // update timePos for next callback 616 if (d_isNotZero(fLastPositionData.speed)) 617 { 618 if (fLastPositionData.speed > 0.0) 619 { 620 // playing forwards 621 fLastPositionData.frame += sampleCount; 622 } 623 else 624 { 625 // playing backwards 626 fLastPositionData.frame -= sampleCount; 627 628 if (fLastPositionData.frame < 0) 629 fLastPositionData.frame = 0; 630 } 631 632 fTimePosition.frame = fLastPositionData.frame; 633 634 if (fTimePosition.bbt.valid) 635 { 636 const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; 637 const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; 638 const double addedBarBeats = double(sampleCount) / framesPerBeat; 639 640 if (fLastPositionData.barBeat >= 0.0f) 641 { 642 fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, 643 (double)fLastPositionData.beatsPerBar); 644 645 const double rest = std::fmod(fLastPositionData.barBeat, 1.0f); 646 fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat-rest+1.0); 647 fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; 648 649 if (fLastPositionData.bar >= 0) 650 { 651 fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ 652 fLastPositionData.beatsPerBar); 653 654 if (fLastPositionData.bar < 0) 655 fLastPositionData.bar = 0; 656 657 fTimePosition.bbt.bar = fLastPositionData.bar + 1; 658 659 fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* 660 fTimePosition.bbt.beatsPerBar* 661 (fTimePosition.bbt.bar-1); 662 } 663 } 664 665 fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); 666 } 667 668 fPlugin.setTimePosition(fTimePosition); 669 } 670 #endif 671 } 672 673 updateParameterOutputsAndTriggers(); 674 675 #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI 676 fEventsOutData.initIfNeeded(fURIDs.atomSequence); 677 678 LV2_Atom_Event* aev; 679 const uint32_t capacity = fEventsOutData.capacity; 680 681 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) 682 { 683 if (! fNeededUiSends[i]) 684 continue; 685 686 const String& curKey(fPlugin.getStateKey(i)); 687 688 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) 689 { 690 const String& key(cit->first); 691 692 if (curKey != key) 693 continue; 694 695 const String& value(cit->second); 696 697 // set msg size (key + value + separator + 2x null terminator) 698 const size_t msgSize = key.length()+value.length()+3; 699 700 if (sizeof(LV2_Atom_Event) + msgSize > capacity - fEventsOutData.offset) 701 { 702 d_stdout("Sending key '%s' to UI failed, out of space", key.buffer()); 703 break; 704 } 705 706 // put data 707 aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + fEventsOutData.offset); 708 aev->time.frames = 0; 709 aev->body.type = fURIDs.dpfKeyValue; 710 aev->body.size = msgSize; 711 712 uint8_t* const msgBuf = LV2_ATOM_BODY(&aev->body); 713 std::memset(msgBuf, 0, msgSize); 714 715 // write key and value in atom buffer 716 std::memcpy(msgBuf, key.buffer(), key.length()+1); 717 std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); 718 719 fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); 720 721 fNeededUiSends[i] = false; 722 break; 723 } 724 } 725 #endif 726 727 #if DISTRHO_LV2_USE_EVENTS_OUT 728 fEventsOutData.endRun(); 729 #endif 730 } 731 732 // ------------------------------------------------------------------- 733 734 uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) 735 { 736 // currently unused 737 return LV2_OPTIONS_ERR_UNKNOWN; 738 } 739 740 uint32_t lv2_set_options(const LV2_Options_Option* const options) 741 { 742 for (int i=0; options[i].key != 0; ++i) 743 { 744 if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) 745 { 746 if (options[i].type == fURIDs.atomInt) 747 { 748 const int32_t bufferSize(*(const int32_t*)options[i].value); 749 fPlugin.setBufferSize(bufferSize); 750 } 751 else 752 { 753 d_stderr("Host changed nominalBlockLength but with wrong value type"); 754 } 755 } 756 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! fUsingNominal) 757 { 758 if (options[i].type == fURIDs.atomInt) 759 { 760 const int32_t bufferSize(*(const int32_t*)options[i].value); 761 fPlugin.setBufferSize(bufferSize); 762 } 763 else 764 { 765 d_stderr("Host changed maxBlockLength but with wrong value type"); 766 } 767 } 768 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_PARAMETERS__sampleRate)) 769 { 770 if (options[i].type == fURIDs.atomFloat) 771 { 772 const float sampleRate(*(const float*)options[i].value); 773 fSampleRate = sampleRate; 774 fPlugin.setSampleRate(sampleRate); 775 } 776 else 777 { 778 d_stderr("Host changed sampleRate but with wrong value type"); 779 } 780 } 781 } 782 783 return LV2_OPTIONS_SUCCESS; 784 } 785 786 // ------------------------------------------------------------------- 787 788 #if DISTRHO_PLUGIN_WANT_PROGRAMS 789 const LV2_Program_Descriptor* lv2_get_program(const uint32_t index) 790 { 791 if (index >= fPlugin.getProgramCount()) 792 return nullptr; 793 794 static LV2_Program_Descriptor desc; 795 796 desc.bank = index / 128; 797 desc.program = index % 128; 798 desc.name = fPlugin.getProgramName(index); 799 800 return &desc; 801 } 802 803 void lv2_select_program(const uint32_t bank, const uint32_t program) 804 { 805 const uint32_t realProgram(bank * 128 + program); 806 807 if (realProgram >= fPlugin.getProgramCount()) 808 return; 809 810 fPlugin.loadProgram(realProgram); 811 812 // Update control inputs 813 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 814 { 815 if (fPlugin.isParameterOutput(i)) 816 continue; 817 818 fLastControlValues[i] = fPlugin.getParameterValue(i); 819 820 setPortControlValue(i, fLastControlValues[i]); 821 } 822 823 # if DISTRHO_PLUGIN_WANT_FULL_STATE 824 // Update state 825 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) 826 { 827 const String& key = cit->first; 828 fStateMap[key] = fPlugin.getState(key); 829 } 830 # endif 831 } 832 #endif 833 834 // ------------------------------------------------------------------- 835 836 #if DISTRHO_PLUGIN_WANT_STATE 837 LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle) 838 { 839 # if DISTRHO_PLUGIN_WANT_FULL_STATE 840 // Update current state 841 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) 842 { 843 const String& key = cit->first; 844 fStateMap[key] = fPlugin.getState(key); 845 } 846 # endif 847 848 String dpf_lv2_key; 849 LV2_URID urid; 850 851 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) 852 { 853 const String& curKey(fPlugin.getStateKey(i)); 854 855 for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) 856 { 857 const String& key(cit->first); 858 859 if (curKey != key) 860 continue; 861 862 const String& value(cit->second); 863 864 # if DISTRHO_PLUGIN_WANT_STATEFILES 865 if (fPlugin.isStateFile(i)) 866 { 867 dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; 868 urid = fURIDs.atomPath; 869 } 870 else 871 # endif 872 { 873 dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; 874 urid = fURIDs.atomString; 875 } 876 877 dpf_lv2_key += key; 878 879 // some hosts need +1 for the null terminator, even though the type is string 880 store(handle, 881 fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), 882 value.buffer(), 883 value.length()+1, 884 urid, 885 LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE); 886 } 887 } 888 889 return LV2_STATE_SUCCESS; 890 } 891 892 LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle) 893 { 894 size_t size; 895 uint32_t type, flags; 896 897 String dpf_lv2_key; 898 LV2_URID urid; 899 900 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) 901 { 902 const String& key(fPlugin.getStateKey(i)); 903 904 # if DISTRHO_PLUGIN_WANT_STATEFILES 905 if (fPlugin.isStateFile(i)) 906 { 907 dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; 908 urid = fURIDs.atomPath; 909 } 910 else 911 # endif 912 { 913 dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; 914 urid = fURIDs.atomString; 915 } 916 917 dpf_lv2_key += key; 918 919 size = 0; 920 type = 0; 921 flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; 922 const void* data = retrieve(handle, 923 fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), 924 &size, &type, &flags); 925 926 if (data == nullptr || size == 0) 927 continue; 928 929 DISTRHO_SAFE_ASSERT_CONTINUE(type == urid); 930 931 const char* const value = (const char*)data; 932 const std::size_t length = std::strlen(value); 933 DISTRHO_SAFE_ASSERT_CONTINUE(length == size || length+1 == size); 934 935 setState(key, value); 936 937 #if DISTRHO_LV2_USE_EVENTS_OUT 938 // signal msg needed for UI 939 fNeededUiSends[i] = true; 940 #endif 941 } 942 943 return LV2_STATE_SUCCESS; 944 } 945 946 // ------------------------------------------------------------------- 947 948 LV2_Worker_Status lv2_work(const void* const data) 949 { 950 const LV2_Atom* const eventBody = (const LV2_Atom*)data; 951 952 if (eventBody->type == fURIDs.dpfKeyValue) 953 { 954 const char* const key = (const char*)(eventBody + 1); 955 const char* const value = key + (std::strlen(key) + 1U); 956 957 setState(key, value); 958 return LV2_WORKER_SUCCESS; 959 } 960 961 # if DISTRHO_PLUGIN_WANT_STATEFILES 962 if (eventBody->type == fURIDs.atomObject) 963 { 964 const LV2_Atom_Object* const object = (const LV2_Atom_Object*)eventBody; 965 966 const LV2_Atom* property = nullptr; 967 const LV2_Atom* value = nullptr; 968 lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); 969 DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN); 970 DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN); 971 DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN); 972 DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath, LV2_WORKER_ERR_UNKNOWN); 973 974 const LV2_URID urid = ((const LV2_Atom_URID*)property)->body; 975 const char* const filename = (const char*)(value + 1); 976 977 String key; 978 979 try { 980 key = fUridStateFileMap[urid]; 981 } DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateFileMap[urid]", LV2_WORKER_ERR_UNKNOWN); 982 983 setState(key, filename); 984 985 for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) 986 { 987 if (fPlugin.getStateKey(i) == key) 988 { 989 fNeededUiSends[i] = true; 990 break; 991 } 992 } 993 994 return LV2_WORKER_SUCCESS; 995 } 996 # endif 997 998 return LV2_WORKER_ERR_UNKNOWN; 999 } 1000 1001 LV2_Worker_Status lv2_work_response(uint32_t, const void*) 1002 { 1003 return LV2_WORKER_SUCCESS; 1004 } 1005 #endif 1006 1007 // ------------------------------------------------------------------- 1008 1009 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1010 void* lv2_get_instance_pointer() 1011 { 1012 return fPlugin.getInstancePointer(); 1013 } 1014 #endif 1015 1016 // ------------------------------------------------------------------- 1017 1018 private: 1019 PluginExporter fPlugin; 1020 const bool fUsingNominal; // if false use maxBlockLength 1021 1022 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 1023 uint32_t fRunCount; 1024 #endif 1025 1026 // LV2 ports 1027 #if DISTRHO_PLUGIN_NUM_INPUTS > 0 1028 const float* fPortAudioIns[DISTRHO_PLUGIN_NUM_INPUTS]; 1029 #else 1030 const float** fPortAudioIns; 1031 #endif 1032 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 1033 float* fPortAudioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; 1034 #else 1035 float** fPortAudioOuts; 1036 #endif 1037 float** fPortControls; 1038 #if DISTRHO_LV2_USE_EVENTS_IN 1039 LV2_Atom_Sequence* fPortEventsIn; 1040 #endif 1041 #if DISTRHO_PLUGIN_WANT_LATENCY 1042 float* fPortLatency; 1043 #endif 1044 1045 // Temporary data 1046 float* fLastControlValues; 1047 double fSampleRate; 1048 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT 1049 MidiEvent fMidiEvents[kMaxMidiEvents]; 1050 #endif 1051 #if DISTRHO_PLUGIN_WANT_TIMEPOS 1052 TimePosition fTimePosition; 1053 1054 struct Lv2PositionData { 1055 int64_t bar; 1056 float barBeat; 1057 uint32_t beatUnit; 1058 float beatsPerBar; 1059 float beatsPerMinute; 1060 int64_t frame; 1061 double speed; 1062 double ticksPerBeat; 1063 1064 Lv2PositionData() 1065 : bar(-1), 1066 barBeat(-1.0f), 1067 beatUnit(0), 1068 beatsPerBar(0.0f), 1069 beatsPerMinute(0.0f), 1070 frame(-1), 1071 speed(0.0), 1072 ticksPerBeat(-1.0) {} 1073 1074 } fLastPositionData; 1075 #endif 1076 1077 #if DISTRHO_LV2_USE_EVENTS_OUT 1078 struct Lv2EventsOutData { 1079 uint32_t capacity, offset; 1080 LV2_Atom_Sequence* port; 1081 1082 Lv2EventsOutData() 1083 : capacity(0), 1084 offset(0), 1085 port(nullptr) {} 1086 1087 void initIfNeeded(const LV2_URID uridAtomSequence) 1088 { 1089 if (capacity != 0) 1090 return; 1091 1092 capacity = port->atom.size; 1093 1094 port->atom.size = sizeof(LV2_Atom_Sequence_Body); 1095 port->atom.type = uridAtomSequence; 1096 port->body.unit = 0; 1097 port->body.pad = 0; 1098 } 1099 1100 void growBy(const uint32_t size) 1101 { 1102 offset += size; 1103 port->atom.size += size; 1104 } 1105 1106 void endRun() 1107 { 1108 capacity = 0; 1109 offset = 0; 1110 } 1111 1112 } fEventsOutData; 1113 #endif 1114 1115 // LV2 URIDs 1116 struct URIDs { 1117 const LV2_URID_Map* _uridMap; 1118 LV2_URID atomBlank; 1119 LV2_URID atomObject; 1120 LV2_URID atomDouble; 1121 LV2_URID atomFloat; 1122 LV2_URID atomInt; 1123 LV2_URID atomLong; 1124 LV2_URID atomPath; 1125 LV2_URID atomSequence; 1126 LV2_URID atomString; 1127 LV2_URID atomURID; 1128 LV2_URID dpfKeyValue; 1129 LV2_URID midiEvent; 1130 LV2_URID patchProperty; 1131 LV2_URID patchValue; 1132 LV2_URID timePosition; 1133 LV2_URID timeBar; 1134 LV2_URID timeBarBeat; 1135 LV2_URID timeBeatUnit; 1136 LV2_URID timeBeatsPerBar; 1137 LV2_URID timeBeatsPerMinute; 1138 LV2_URID timeTicksPerBeat; 1139 LV2_URID timeFrame; 1140 LV2_URID timeSpeed; 1141 1142 URIDs(const LV2_URID_Map* const uridMap) 1143 : _uridMap(uridMap), 1144 atomBlank(map(LV2_ATOM__Blank)), 1145 atomObject(map(LV2_ATOM__Object)), 1146 atomDouble(map(LV2_ATOM__Double)), 1147 atomFloat(map(LV2_ATOM__Float)), 1148 atomInt(map(LV2_ATOM__Int)), 1149 atomLong(map(LV2_ATOM__Long)), 1150 atomPath(map(LV2_ATOM__Path)), 1151 atomSequence(map(LV2_ATOM__Sequence)), 1152 atomString(map(LV2_ATOM__String)), 1153 atomURID(map(LV2_ATOM__URID)), 1154 dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")), 1155 midiEvent(map(LV2_MIDI__MidiEvent)), 1156 patchProperty(map(LV2_PATCH__property)), 1157 patchValue(map(LV2_PATCH__value)), 1158 timePosition(map(LV2_TIME__Position)), 1159 timeBar(map(LV2_TIME__bar)), 1160 timeBarBeat(map(LV2_TIME__barBeat)), 1161 timeBeatUnit(map(LV2_TIME__beatUnit)), 1162 timeBeatsPerBar(map(LV2_TIME__beatsPerBar)), 1163 timeBeatsPerMinute(map(LV2_TIME__beatsPerMinute)), 1164 timeTicksPerBeat(map(LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat)), 1165 timeFrame(map(LV2_TIME__frame)), 1166 timeSpeed(map(LV2_TIME__speed)) {} 1167 1168 inline LV2_URID map(const char* const uri) const 1169 { 1170 return _uridMap->map(_uridMap->handle, uri); 1171 } 1172 } fURIDs; 1173 1174 // LV2 features 1175 const LV2_URID_Map* const fUridMap; 1176 const LV2_Worker_Schedule* const fWorker; 1177 1178 #if DISTRHO_PLUGIN_WANT_STATE 1179 StringToStringMap fStateMap; 1180 bool* fNeededUiSends; 1181 1182 void setState(const char* const key, const char* const newValue) 1183 { 1184 fPlugin.setState(key, newValue); 1185 1186 // check if we want to save this key 1187 if (! fPlugin.wantStateKey(key)) 1188 return; 1189 1190 // check if key already exists 1191 for (StringToStringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it) 1192 { 1193 const String& dkey(it->first); 1194 1195 if (dkey == key) 1196 { 1197 it->second = newValue; 1198 return; 1199 } 1200 } 1201 1202 d_stderr("Failed to find plugin state with key \"%s\"", key); 1203 } 1204 1205 # if DISTRHO_PLUGIN_WANT_STATEFILES 1206 UridToStringMap fUridStateFileMap; 1207 # endif 1208 #endif 1209 1210 void updateParameterOutputsAndTriggers() 1211 { 1212 float curValue; 1213 1214 for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) 1215 { 1216 if (fPlugin.isParameterOutput(i)) 1217 { 1218 curValue = fLastControlValues[i] = fPlugin.getParameterValue(i); 1219 1220 setPortControlValue(i, curValue); 1221 } 1222 else if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) 1223 { 1224 // NOTE: host is responsible for auto-updating control port buffers 1225 } 1226 } 1227 1228 #if DISTRHO_PLUGIN_WANT_LATENCY 1229 if (fPortLatency != nullptr) 1230 *fPortLatency = fPlugin.getLatency(); 1231 #endif 1232 } 1233 1234 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 1235 bool writeMidi(const MidiEvent& midiEvent) 1236 { 1237 DISTRHO_SAFE_ASSERT_RETURN(fEventsOutData.port != nullptr, false); 1238 1239 fEventsOutData.initIfNeeded(fURIDs.atomSequence); 1240 1241 const uint32_t capacity = fEventsOutData.capacity; 1242 const uint32_t offset = fEventsOutData.offset; 1243 1244 if (sizeof(LV2_Atom_Event) + midiEvent.size > capacity - offset) 1245 return false; 1246 1247 LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + offset); 1248 aev->time.frames = midiEvent.frame; 1249 aev->body.type = fURIDs.midiEvent; 1250 aev->body.size = midiEvent.size; 1251 std::memcpy(LV2_ATOM_BODY(&aev->body), 1252 midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data, 1253 midiEvent.size); 1254 1255 fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + midiEvent.size)); 1256 1257 return true; 1258 } 1259 1260 static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) 1261 { 1262 return ((PluginLv2*)ptr)->writeMidi(midiEvent); 1263 } 1264 #endif 1265 }; 1266 1267 // ----------------------------------------------------------------------- 1268 1269 static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* features) 1270 { 1271 const LV2_Options_Option* options = nullptr; 1272 const LV2_URID_Map* uridMap = nullptr; 1273 const LV2_Worker_Schedule* worker = nullptr; 1274 1275 for (int i=0; features[i] != nullptr; ++i) 1276 { 1277 if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0) 1278 options = (const LV2_Options_Option*)features[i]->data; 1279 else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0) 1280 uridMap = (const LV2_URID_Map*)features[i]->data; 1281 else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0) 1282 worker = (const LV2_Worker_Schedule*)features[i]->data; 1283 } 1284 1285 if (options == nullptr) 1286 { 1287 d_stderr("Options feature missing, cannot continue!"); 1288 return nullptr; 1289 } 1290 1291 if (uridMap == nullptr) 1292 { 1293 d_stderr("URID Map feature missing, cannot continue!"); 1294 return nullptr; 1295 } 1296 1297 #if DISTRHO_PLUGIN_WANT_STATE 1298 if (worker == nullptr) 1299 { 1300 d_stderr("Worker feature missing, cannot continue!"); 1301 return nullptr; 1302 } 1303 #endif 1304 1305 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 1306 mod_license_check(features, DISTRHO_PLUGIN_URI); 1307 #endif 1308 1309 d_lastBufferSize = 0; 1310 bool usingNominal = false; 1311 1312 for (int i=0; options[i].key != 0; ++i) 1313 { 1314 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength)) 1315 { 1316 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) 1317 { 1318 d_lastBufferSize = *(const int*)options[i].value; 1319 usingNominal = true; 1320 } 1321 else 1322 { 1323 d_stderr("Host provides nominalBlockLength but has wrong value type"); 1324 } 1325 break; 1326 } 1327 1328 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) 1329 { 1330 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) 1331 d_lastBufferSize = *(const int*)options[i].value; 1332 else 1333 d_stderr("Host provides maxBlockLength but has wrong value type"); 1334 1335 // no break, continue in case host supports nominalBlockLength 1336 } 1337 } 1338 1339 if (d_lastBufferSize == 0) 1340 { 1341 d_stderr("Host does not provide nominalBlockLength or maxBlockLength options"); 1342 d_lastBufferSize = 2048; 1343 } 1344 1345 d_lastSampleRate = sampleRate; 1346 1347 return new PluginLv2(sampleRate, uridMap, worker, usingNominal); 1348 } 1349 1350 #define instancePtr ((PluginLv2*)instance) 1351 1352 static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation) 1353 { 1354 instancePtr->lv2_connect_port(port, dataLocation); 1355 } 1356 1357 static void lv2_activate(LV2_Handle instance) 1358 { 1359 instancePtr->lv2_activate(); 1360 } 1361 1362 static void lv2_run(LV2_Handle instance, uint32_t sampleCount) 1363 { 1364 instancePtr->lv2_run(sampleCount); 1365 } 1366 1367 static void lv2_deactivate(LV2_Handle instance) 1368 { 1369 instancePtr->lv2_deactivate(); 1370 } 1371 1372 static void lv2_cleanup(LV2_Handle instance) 1373 { 1374 delete instancePtr; 1375 } 1376 1377 // ----------------------------------------------------------------------- 1378 1379 static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options) 1380 { 1381 return instancePtr->lv2_get_options(options); 1382 } 1383 1384 static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options) 1385 { 1386 return instancePtr->lv2_set_options(options); 1387 } 1388 1389 // ----------------------------------------------------------------------- 1390 1391 #if DISTRHO_PLUGIN_WANT_PROGRAMS 1392 static const LV2_Program_Descriptor* lv2_get_program(LV2_Handle instance, uint32_t index) 1393 { 1394 return instancePtr->lv2_get_program(index); 1395 } 1396 1397 static void lv2_select_program(LV2_Handle instance, uint32_t bank, uint32_t program) 1398 { 1399 instancePtr->lv2_select_program(bank, program); 1400 } 1401 #endif 1402 1403 // ----------------------------------------------------------------------- 1404 1405 #if DISTRHO_PLUGIN_WANT_STATE 1406 static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t, const LV2_Feature* const*) 1407 { 1408 return instancePtr->lv2_save(store, handle); 1409 } 1410 1411 static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t, const LV2_Feature* const*) 1412 { 1413 return instancePtr->lv2_restore(retrieve, handle); 1414 } 1415 1416 LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data) 1417 { 1418 return instancePtr->lv2_work(data); 1419 } 1420 1421 LV2_Worker_Status lv2_work_response(LV2_Handle instance, uint32_t size, const void* body) 1422 { 1423 return instancePtr->lv2_work_response(size, body); 1424 } 1425 #endif 1426 1427 // ----------------------------------------------------------------------- 1428 1429 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1430 static void* lv2_get_instance_pointer(LV2_Handle instance) 1431 { 1432 return instancePtr->lv2_get_instance_pointer(); 1433 } 1434 #endif 1435 1436 // ----------------------------------------------------------------------- 1437 1438 static const void* lv2_extension_data(const char* uri) 1439 { 1440 static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; 1441 1442 if (std::strcmp(uri, LV2_OPTIONS__interface) == 0) 1443 return &options; 1444 1445 #if DISTRHO_PLUGIN_WANT_PROGRAMS 1446 static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program }; 1447 1448 if (std::strcmp(uri, LV2_PROGRAMS__Interface) == 0) 1449 return &programs; 1450 #endif 1451 1452 #if DISTRHO_PLUGIN_WANT_STATE 1453 static const LV2_State_Interface state = { lv2_save, lv2_restore }; 1454 static const LV2_Worker_Interface worker = { lv2_work, lv2_work_response, nullptr }; 1455 1456 if (std::strcmp(uri, LV2_STATE__interface) == 0) 1457 return &state; 1458 if (std::strcmp(uri, LV2_WORKER__interface) == 0) 1459 return &worker; 1460 #endif 1461 1462 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 1463 struct LV2_DirectAccess_Interface { 1464 void* (*get_instance_pointer)(LV2_Handle handle); 1465 }; 1466 1467 static const LV2_DirectAccess_Interface directaccess = { lv2_get_instance_pointer }; 1468 1469 if (std::strcmp(uri, DISTRHO_PLUGIN_LV2_STATE_PREFIX "direct-access") == 0) 1470 return &directaccess; 1471 #endif 1472 1473 #ifdef DISTRHO_PLUGIN_LICENSED_FOR_MOD 1474 return mod_license_interface(uri); 1475 #else 1476 return nullptr; 1477 #endif 1478 } 1479 1480 #undef instancePtr 1481 1482 // ----------------------------------------------------------------------- 1483 1484 static const LV2_Descriptor sLv2Descriptor = { 1485 DISTRHO_PLUGIN_URI, 1486 lv2_instantiate, 1487 lv2_connect_port, 1488 lv2_activate, 1489 lv2_run, 1490 lv2_deactivate, 1491 lv2_cleanup, 1492 lv2_extension_data 1493 }; 1494 1495 // ----------------------------------------------------------------------- 1496 1497 END_NAMESPACE_DISTRHO 1498 1499 DISTRHO_PLUGIN_EXPORT 1500 const LV2_Descriptor* lv2_descriptor(uint32_t index) 1501 { 1502 USE_NAMESPACE_DISTRHO 1503 return (index == 0) ? &sLv2Descriptor : nullptr; 1504 } 1505 1506 // ----------------------------------------------------------------------- 1507