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