DistrhoPluginCarla.cpp (15714B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2022 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_HAS_UI 20 # include "DistrhoUIInternal.hpp" 21 #endif 22 23 #include "CarlaNative.hpp" 24 25 // TODO 26 #undef DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 27 #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0 28 29 // ----------------------------------------------------------------------- 30 31 START_NAMESPACE_DISTRHO 32 33 #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 34 static constexpr const writeMidiFunc writeMidiCallback = nullptr; 35 #endif 36 #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 37 static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; 38 #endif 39 // TODO 40 static constexpr const updateStateValueFunc updateStateValueCallback = nullptr; 41 42 #if DISTRHO_PLUGIN_HAS_UI 43 // ----------------------------------------------------------------------- 44 // Carla UI 45 46 #if ! DISTRHO_PLUGIN_WANT_STATE 47 static const setStateFunc setStateCallback = nullptr; 48 #endif 49 #if ! DISTRHO_PLUGIN_IS_SYNTH 50 static const sendNoteFunc sendNoteCallback = nullptr; 51 #endif 52 53 class UICarla 54 { 55 public: 56 UICarla(const NativeHostDescriptor* const host, PluginExporter* const plugin) 57 : fHost(host), 58 fUI(this, 0, plugin->getSampleRate(), 59 editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, 60 nullptr, // window size 61 nullptr, // TODO file request 62 nullptr, // bundle path 63 plugin->getInstancePointer()) 64 { 65 fUI.setWindowTitle(host->uiName); 66 67 if (host->uiParentId != 0) 68 fUI.setWindowTransientWinId(host->uiParentId); 69 } 70 71 ~UICarla() 72 { 73 fUI.quit(); 74 } 75 76 // --------------------------------------------- 77 78 void carla_show(const bool yesNo) 79 { 80 fUI.setWindowVisible(yesNo); 81 } 82 83 bool carla_idle() 84 { 85 return fUI.plugin_idle(); 86 } 87 88 void carla_setParameterValue(const uint32_t index, const float value) 89 { 90 fUI.parameterChanged(index, value); 91 } 92 93 #if DISTRHO_PLUGIN_WANT_PROGRAMS 94 void carla_setMidiProgram(const uint32_t realProgram) 95 { 96 fUI.programLoaded(realProgram); 97 } 98 #endif 99 100 #if DISTRHO_PLUGIN_WANT_STATE 101 void carla_setCustomData(const char* const key, const char* const value) 102 { 103 fUI.stateChanged(key, value); 104 } 105 #endif 106 107 void carla_setUiTitle(const char* const uiTitle) 108 { 109 fUI.setWindowTitle(uiTitle); 110 } 111 112 // --------------------------------------------- 113 114 protected: 115 void handleEditParameter(const uint32_t, const bool) 116 { 117 // TODO 118 } 119 120 void handleSetParameterValue(const uint32_t rindex, const float value) 121 { 122 fHost->ui_parameter_changed(fHost->handle, rindex, value); 123 } 124 125 #if DISTRHO_PLUGIN_WANT_STATE 126 void handleSetState(const char* const key, const char* const value) 127 { 128 fHost->ui_custom_data_changed(fHost->handle, key, value); 129 } 130 #endif 131 132 #if DISTRHO_PLUGIN_IS_SYNTH 133 void handleSendNote(const uint8_t, const uint8_t, const uint8_t) 134 { 135 // TODO 136 } 137 #endif 138 139 // --------------------------------------------- 140 141 private: 142 // Plugin stuff 143 const NativeHostDescriptor* const fHost; 144 145 // UI 146 UIExporter fUI; 147 148 // --------------------------------------------- 149 // Callbacks 150 151 #define handlePtr ((UICarla*)ptr) 152 153 static void editParameterCallback(void* ptr, uint32_t index, bool started) 154 { 155 handlePtr->handleEditParameter(index, started); 156 } 157 158 static void setParameterCallback(void* ptr, uint32_t rindex, float value) 159 { 160 handlePtr->handleSetParameterValue(rindex, value); 161 } 162 163 #if DISTRHO_PLUGIN_WANT_STATE 164 static void setStateCallback(void* ptr, const char* key, const char* value) 165 { 166 handlePtr->handleSetState(key, value); 167 } 168 #endif 169 170 #if DISTRHO_PLUGIN_IS_SYNTH 171 static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity) 172 { 173 handlePtr->handleSendNote(channel, note, velocity); 174 } 175 #endif 176 177 #undef handlePtr 178 179 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla) 180 }; 181 #endif // DISTRHO_PLUGIN_HAS_UI 182 183 // ----------------------------------------------------------------------- 184 // Carla Plugin 185 186 class PluginCarla : public NativePluginClass 187 { 188 public: 189 PluginCarla(const NativeHostDescriptor* const host) 190 : NativePluginClass(host), 191 fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback), 192 fScalePointsCache(nullptr) 193 { 194 #if DISTRHO_PLUGIN_HAS_UI 195 fUiPtr = nullptr; 196 #endif 197 } 198 199 ~PluginCarla() override 200 { 201 #if DISTRHO_PLUGIN_HAS_UI 202 if (fUiPtr != nullptr) 203 { 204 delete fUiPtr; 205 fUiPtr = nullptr; 206 } 207 #endif 208 209 if (fScalePointsCache != nullptr) 210 { 211 delete[] fScalePointsCache; 212 fScalePointsCache = nullptr; 213 } 214 } 215 216 protected: 217 // ------------------------------------------------------------------- 218 // Plugin parameter calls 219 220 uint32_t getParameterCount() const override 221 { 222 return fPlugin.getParameterCount(); 223 } 224 225 const NativeParameter* getParameterInfo(const uint32_t index) const override 226 { 227 CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), nullptr); 228 229 static NativeParameter param; 230 231 param.scalePointCount = 0; 232 param.scalePoints = nullptr; 233 234 { 235 int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED; 236 const uint32_t paramHints = fPlugin.getParameterHints(index); 237 238 if (paramHints & kParameterIsAutomatable) 239 nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE; 240 if (paramHints & kParameterIsBoolean) 241 nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN; 242 if (paramHints & kParameterIsInteger) 243 nativeParamHints |= ::NATIVE_PARAMETER_IS_INTEGER; 244 if (paramHints & kParameterIsLogarithmic) 245 nativeParamHints |= ::NATIVE_PARAMETER_IS_LOGARITHMIC; 246 if (paramHints & kParameterIsOutput) 247 nativeParamHints |= ::NATIVE_PARAMETER_IS_OUTPUT; 248 249 param.hints = static_cast<NativeParameterHints>(nativeParamHints); 250 } 251 252 param.name = fPlugin.getParameterName(index); 253 param.unit = fPlugin.getParameterUnit(index); 254 255 { 256 const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); 257 258 param.ranges.def = ranges.def; 259 param.ranges.min = ranges.min; 260 param.ranges.max = ranges.max; 261 } 262 263 { 264 const ParameterEnumerationValues& enumValues(fPlugin.getParameterEnumValues(index)); 265 266 if (const uint32_t scalePointCount = enumValues.count) 267 { 268 NativeParameterScalePoint* const scalePoints = new NativeParameterScalePoint[scalePointCount]; 269 270 for (uint32_t i=0; i<scalePointCount; ++i) 271 { 272 scalePoints[i].label = enumValues.values[i].label.buffer(); 273 scalePoints[i].value = enumValues.values[i].value; 274 } 275 276 param.scalePoints = scalePoints; 277 param.scalePointCount = scalePointCount; 278 279 if (enumValues.restrictedMode) 280 param.hints = static_cast<NativeParameterHints>(param.hints|::NATIVE_PARAMETER_USES_SCALEPOINTS); 281 } 282 else if (fScalePointsCache != nullptr) 283 { 284 delete[] fScalePointsCache; 285 fScalePointsCache = nullptr; 286 } 287 } 288 289 return ¶m; 290 } 291 292 float getParameterValue(const uint32_t index) const override 293 { 294 CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(), 0.0f); 295 296 return fPlugin.getParameterValue(index); 297 } 298 299 // ------------------------------------------------------------------- 300 // Plugin midi-program calls 301 302 #if DISTRHO_PLUGIN_WANT_PROGRAMS 303 uint32_t getMidiProgramCount() const override 304 { 305 return fPlugin.getProgramCount(); 306 } 307 308 const NativeMidiProgram* getMidiProgramInfo(const uint32_t index) const override 309 { 310 CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(), nullptr); 311 312 static NativeMidiProgram midiProgram; 313 314 midiProgram.bank = index / 128; 315 midiProgram.program = index % 128; 316 midiProgram.name = fPlugin.getProgramName(index); 317 318 return &midiProgram; 319 } 320 #endif 321 322 // ------------------------------------------------------------------- 323 // Plugin state calls 324 325 void setParameterValue(const uint32_t index, const float value) override 326 { 327 CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),); 328 329 fPlugin.setParameterValue(index, value); 330 } 331 332 #if DISTRHO_PLUGIN_WANT_PROGRAMS 333 void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override 334 { 335 const uint32_t realProgram(bank * 128 + program); 336 337 CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),); 338 339 fPlugin.loadProgram(realProgram); 340 } 341 #endif 342 343 #if DISTRHO_PLUGIN_WANT_STATE 344 void setCustomData(const char* const key, const char* const value) override 345 { 346 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); 347 CARLA_SAFE_ASSERT_RETURN(value != nullptr,); 348 349 fPlugin.setState(key, value); 350 } 351 #endif 352 353 // ------------------------------------------------------------------- 354 // Plugin process calls 355 356 void activate() override 357 { 358 fPlugin.activate(); 359 } 360 361 void deactivate() override 362 { 363 fPlugin.deactivate(); 364 } 365 366 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT 367 void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, 368 const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override 369 { 370 MidiEvent realMidiEvents[midiEventCount]; 371 372 for (uint32_t i=0; i < midiEventCount; ++i) 373 { 374 const NativeMidiEvent& midiEvent(midiEvents[i]); 375 MidiEvent& realMidiEvent(realMidiEvents[i]); 376 377 realMidiEvent.frame = midiEvent.time; 378 realMidiEvent.size = midiEvent.size; 379 380 uint8_t j=0; 381 for (; j<midiEvent.size; ++j) 382 realMidiEvent.data[j] = midiEvent.data[j]; 383 for (; j<midiEvent.size; ++j) 384 realMidiEvent.data[j] = midiEvent.data[j]; 385 386 realMidiEvent.dataExt = nullptr; 387 } 388 389 fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames, realMidiEvents, midiEventCount); 390 } 391 #else 392 void process(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, 393 const NativeMidiEvent* const, const uint32_t) override 394 { 395 fPlugin.run(const_cast<const float**>(inBuffer), outBuffer, frames); 396 } 397 #endif 398 399 // ------------------------------------------------------------------- 400 // Plugin UI calls 401 402 #if DISTRHO_PLUGIN_HAS_UI 403 void uiShow(const bool show) override 404 { 405 if (show) 406 { 407 createUiIfNeeded(); 408 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 409 410 fUiPtr->carla_show(show); 411 } 412 else if (fUiPtr != nullptr) 413 { 414 delete fUiPtr; 415 fUiPtr = nullptr; 416 } 417 } 418 419 void uiIdle() override 420 { 421 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 422 423 if (! fUiPtr->carla_idle()) 424 { 425 uiClosed(); 426 427 delete fUiPtr; 428 fUiPtr = nullptr; 429 } 430 } 431 432 void uiSetParameterValue(const uint32_t index, const float value) override 433 { 434 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 435 CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),); 436 437 fUiPtr->carla_setParameterValue(index, value); 438 } 439 440 # if DISTRHO_PLUGIN_WANT_PROGRAMS 441 void uiSetMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override 442 { 443 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 444 445 const uint32_t realProgram(bank * 128 + program); 446 447 CARLA_SAFE_ASSERT_RETURN(realProgram < getMidiProgramCount(),); 448 449 fUiPtr->carla_setMidiProgram(realProgram); 450 } 451 # endif 452 453 # if DISTRHO_PLUGIN_WANT_STATE 454 void uiSetCustomData(const char* const key, const char* const value) override 455 { 456 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 457 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); 458 CARLA_SAFE_ASSERT_RETURN(value != nullptr,); 459 460 fUiPtr->carla_setCustomData(key, value); 461 } 462 # endif 463 #endif 464 465 // ------------------------------------------------------------------- 466 // Plugin dispatcher calls 467 468 void bufferSizeChanged(const uint32_t bufferSize) override 469 { 470 fPlugin.setBufferSize(bufferSize, true); 471 } 472 473 void sampleRateChanged(const double sampleRate) override 474 { 475 fPlugin.setSampleRate(sampleRate, true); 476 } 477 478 #if DISTRHO_PLUGIN_HAS_UI 479 void uiNameChanged(const char* const uiName) override 480 { 481 CARLA_SAFE_ASSERT_RETURN(fUiPtr != nullptr,); 482 483 fUiPtr->carla_setUiTitle(uiName); 484 } 485 #endif 486 487 // ------------------------------------------------------------------- 488 489 private: 490 PluginExporter fPlugin; 491 mutable NativeParameterScalePoint* fScalePointsCache; 492 493 #if DISTRHO_PLUGIN_HAS_UI 494 // UI 495 UICarla* fUiPtr; 496 497 void createUiIfNeeded() 498 { 499 if (fUiPtr == nullptr) 500 fUiPtr = new UICarla(getHostHandle(), &fPlugin); 501 } 502 #endif 503 504 #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 505 static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) 506 { 507 if (midiEvent.size > 4) 508 return; 509 510 const NativeMidiEvent event = { 511 midiEvent.frame, 0, midiEvent.size, midiEvent.data 512 }; 513 514 return ((PluginCarla*)ptr)->fPlugin.writeMidiEvent(midiEvent); 515 } 516 #endif 517 518 #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 519 bool requestParameterValueChange(const uint32_t index, const float value) 520 { 521 // TODO implementation 522 return false; 523 } 524 525 static bool requestParameterValueChangeCallback(void* ptr, const uint32_t index, const float value) 526 { 527 return thisPtr->requestParameterValueChange(index, value); 528 } 529 #endif 530 531 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginCarla) 532 533 // ------------------------------------------------------------------- 534 535 public: 536 static NativePluginHandle _instantiate(const NativeHostDescriptor* host) 537 { 538 d_nextBufferSize = host->get_buffer_size(host->handle); 539 d_nextSampleRate = host->get_sample_rate(host->handle); 540 return new PluginCarla(host); 541 } 542 543 static void _cleanup(NativePluginHandle handle) 544 { 545 delete (PluginCarla*)handle; 546 } 547 }; 548 549 END_NAMESPACE_DISTRHO 550 551 // -----------------------------------------------------------------------