1 /* 2 * Carla Plugin 3 * Copyright (C) 2011-2019 Filipe Coelho <falktx@falktx.com> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of 8 * the License, or any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * For a full copy of the GNU General Public License see the doc/GPL.txt file. 16 */ 17 18 #ifndef CARLA_PLUGIN_INTERNAL_HPP_INCLUDED 19 #define CARLA_PLUGIN_INTERNAL_HPP_INCLUDED 20 21 #include "CarlaPlugin.hpp" 22 23 #include "CarlaJuceUtils.hpp" 24 #include "CarlaLibUtils.hpp" 25 #include "CarlaStateUtils.hpp" 26 27 #include "CarlaMIDI.h" 28 #include "CarlaMutex.hpp" 29 #include "CarlaString.hpp" 30 #include "RtLinkedList.hpp" 31 32 CARLA_BACKEND_START_NAMESPACE 33 34 // ----------------------------------------------------------------------- 35 // Engine helper macro, sets lastError and returns false/NULL 36 37 #define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return false; } 38 #define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return nullptr; } 39 40 #define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return false; } 41 #define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return nullptr; } 42 43 // ----------------------------------------------------------------------- 44 // Maximum pre-allocated events for some plugin types 45 46 const ushort kPluginMaxMidiEvents = 512; 47 48 // ----------------------------------------------------------------------- 49 // Extra parameter hints, hidden from backend 50 51 const uint PARAMETER_MAPPED_RANGES_SET = 0x10000; 52 const uint PARAMETER_IS_STRICT_BOUNDS = 0x20000; 53 const uint PARAMETER_IS_TRIGGER = 0x40000; 54 55 // ----------------------------------------------------------------------- 56 // Extra plugin hints, hidden from backend 57 58 const uint PLUGIN_EXTRA_HINT_HAS_MIDI_IN = 0x01; 59 const uint PLUGIN_EXTRA_HINT_HAS_MIDI_OUT = 0x02; 60 61 // ----------------------------------------------------------------------- 62 // Special parameters 63 64 enum SpecialParameterType { 65 PARAMETER_SPECIAL_NULL = 0, 66 PARAMETER_SPECIAL_FREEWHEEL = 1, 67 PARAMETER_SPECIAL_LATENCY = 2, 68 PARAMETER_SPECIAL_SAMPLE_RATE = 3, 69 PARAMETER_SPECIAL_TIME = 4 70 }; 71 72 // ----------------------------------------------------------------------- 73 74 /*! 75 * Post-RT event type. 76 * These are events postponned from within the process function, 77 * 78 * During process, we cannot lock, allocate memory or do UI stuff. 79 * Events have to be postponned to be executed later, on a separate thread. 80 * @see PluginPostRtEvent 81 */ 82 enum PluginPostRtEventType { 83 kPluginPostRtEventNull = 0, 84 kPluginPostRtEventParameterChange, 85 kPluginPostRtEventProgramChange, 86 kPluginPostRtEventMidiProgramChange, 87 kPluginPostRtEventNoteOn, 88 kPluginPostRtEventNoteOff, 89 kPluginPostRtEventMidiLearn 90 }; 91 92 /*! 93 * A Post-RT event. 94 * @see PluginPostRtEventType 95 */ 96 struct PluginPostRtEvent { 97 PluginPostRtEventType type; 98 bool sendCallback; 99 union { 100 struct { 101 int32_t index; 102 float value; 103 } parameter; 104 struct { 105 uint32_t index; 106 } program; 107 struct { 108 uint8_t channel; 109 uint8_t note; 110 uint8_t velocity; 111 } note; 112 struct { 113 uint32_t parameter; 114 uint8_t cc; 115 uint8_t channel; 116 } midiLearn; 117 }; 118 }; 119 120 // ----------------------------------------------------------------------- 121 122 struct ExternalMidiNote { 123 int8_t channel; // invalid if -1 124 uint8_t note; // 0 to 127 125 uint8_t velo; // 1 to 127, 0 for note-off 126 }; 127 128 // ----------------------------------------------------------------------- 129 130 struct PluginAudioPort { 131 uint32_t rindex; 132 CarlaEngineAudioPort* port; 133 }; 134 135 struct PluginAudioData { 136 uint32_t count; 137 PluginAudioPort* ports; 138 139 PluginAudioData() noexcept; 140 ~PluginAudioData() noexcept; 141 void createNew(uint32_t newCount); 142 void clear() noexcept; 143 void initBuffers() const noexcept; 144 145 CARLA_DECLARE_NON_COPY_STRUCT(PluginAudioData) 146 }; 147 148 // ----------------------------------------------------------------------- 149 150 struct PluginCVPort { 151 uint32_t rindex; 152 //uint32_t param; // FIXME is this needed? 153 CarlaEngineCVPort* port; 154 }; 155 156 struct PluginCVData { 157 uint32_t count; 158 PluginCVPort* ports; 159 160 PluginCVData() noexcept; 161 ~PluginCVData() noexcept; 162 void createNew(uint32_t newCount); 163 void clear() noexcept; 164 void initBuffers() const noexcept; 165 166 CARLA_DECLARE_NON_COPY_STRUCT(PluginCVData) 167 }; 168 169 // ----------------------------------------------------------------------- 170 171 struct PluginEventData { 172 CarlaEngineEventPort* portIn; 173 CarlaEngineEventPort* portOut; 174 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 175 CarlaEngineCVSourcePorts* cvSourcePorts; 176 #endif 177 178 PluginEventData() noexcept; 179 ~PluginEventData() noexcept; 180 void clear() noexcept; 181 void initBuffers() const noexcept; 182 183 CARLA_DECLARE_NON_COPY_STRUCT(PluginEventData) 184 }; 185 186 // ----------------------------------------------------------------------- 187 188 struct PluginParameterData { 189 uint32_t count; 190 ParameterData* data; 191 ParameterRanges* ranges; 192 SpecialParameterType* special; 193 194 PluginParameterData() noexcept; 195 ~PluginParameterData() noexcept; 196 void createNew(uint32_t newCount, bool withSpecial); 197 void clear() noexcept; 198 float getFixedValue(uint32_t parameterId, float value) const noexcept; 199 float getFinalUnnormalizedValue(uint32_t parameterId, float normalizedValue) const noexcept; 200 float getFinalValueWithMidiDelta(uint32_t parameterId, float value, int8_t delta) const noexcept; 201 202 CARLA_DECLARE_NON_COPY_STRUCT(PluginParameterData) 203 }; 204 205 // ----------------------------------------------------------------------- 206 207 typedef const char* ProgramName; 208 209 struct PluginProgramData { 210 uint32_t count; 211 int32_t current; 212 ProgramName* names; 213 214 PluginProgramData() noexcept; 215 ~PluginProgramData() noexcept; 216 void createNew(uint32_t newCount); 217 void clear() noexcept; 218 219 CARLA_DECLARE_NON_COPY_STRUCT(PluginProgramData) 220 }; 221 222 // ----------------------------------------------------------------------- 223 224 struct PluginMidiProgramData { 225 uint32_t count; 226 int32_t current; 227 MidiProgramData* data; 228 229 PluginMidiProgramData() noexcept; 230 ~PluginMidiProgramData() noexcept; 231 void createNew(uint32_t newCount); 232 void clear() noexcept; 233 const MidiProgramData& getCurrent() const noexcept; 234 235 CARLA_DECLARE_NON_COPY_STRUCT(PluginMidiProgramData) 236 }; 237 238 // ----------------------------------------------------------------------- 239 240 struct CarlaPlugin::ProtectedData { 241 CarlaEngine* const engine; 242 CarlaEngineClient* client; 243 244 uint id; 245 uint hints; 246 uint options; 247 uint32_t nodeId; 248 249 bool active; 250 bool enabled; 251 bool needsReset; 252 253 bool engineBridged; 254 bool enginePlugin; 255 256 lib_t lib; 257 lib_t uiLib; 258 259 // misc 260 int8_t ctrlChannel; 261 uint extraHints; 262 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 263 int32_t midiLearnParameterIndex; 264 uint transientTryCounter; 265 bool transientFirstTry; 266 #endif 267 268 // data 1 269 const char* name; 270 const char* filename; 271 const char* iconName; 272 273 // data 2 274 PluginAudioData audioIn; 275 PluginAudioData audioOut; 276 PluginCVData cvIn; 277 PluginCVData cvOut; 278 PluginEventData event; 279 PluginParameterData param; 280 PluginProgramData prog; 281 PluginMidiProgramData midiprog; 282 LinkedList<CustomData> custom; 283 284 CarlaMutex masterMutex; // global master lock 285 CarlaMutex singleMutex; // small lock used only in processSingle() 286 287 CarlaStateSave stateSave; 288 289 CarlaString uiTitle; 290 291 struct ExternalNotes { 292 CarlaMutex mutex; 293 RtLinkedList<ExternalMidiNote>::Pool dataPool; 294 RtLinkedList<ExternalMidiNote> data; 295 296 ExternalNotes() noexcept; 297 ~ExternalNotes() noexcept; 298 void appendNonRT(const ExternalMidiNote& note) noexcept; 299 void clear() noexcept; 300 301 CARLA_DECLARE_NON_COPY_STRUCT(ExternalNotes) 302 303 } extNotes; 304 305 struct Latency { 306 uint32_t frames; 307 #ifndef BUILD_BRIDGE 308 uint32_t channels; 309 float** buffers; 310 #endif 311 312 Latency() noexcept; 313 #ifndef BUILD_BRIDGE 314 ~Latency() noexcept; 315 void clearBuffers() noexcept; 316 void recreateBuffers(uint32_t newChannels, uint32_t newFrames); 317 #endif 318 319 CARLA_DECLARE_NON_COPY_STRUCT(Latency) 320 321 } latency; 322 323 class PostRtEvents { 324 public: 325 PostRtEvents() noexcept; 326 ~PostRtEvents() noexcept; 327 void appendRT(const PluginPostRtEvent& event) noexcept; 328 void trySplice() noexcept; 329 330 struct Access { AccessCarlaPlugin::ProtectedData::PostRtEvents::Access331 Access(PostRtEvents& e) 332 : data2(e.dataPool), 333 poolMutex(e.poolMutex) 334 { 335 const CarlaMutexLocker cml1(e.dataMutex); 336 const CarlaMutexLocker cml2(e.poolMutex); 337 338 if (e.data.isNotEmpty()) 339 e.data.moveTo(data2, true); 340 } 341 ~AccessCarlaPlugin::ProtectedData::PostRtEvents::Access342 ~Access() 343 { 344 const CarlaMutexLocker cml(poolMutex); 345 346 data2.clear(); 347 } 348 getDataIteratorCarlaPlugin::ProtectedData::PostRtEvents::Access349 inline RtLinkedList<PluginPostRtEvent>::Itenerator getDataIterator() const noexcept 350 { 351 return data2.begin2(); 352 } 353 isEmptyCarlaPlugin::ProtectedData::PostRtEvents::Access354 inline std::size_t isEmpty() const noexcept 355 { 356 return data2.isEmpty(); 357 } 358 359 private: 360 RtLinkedList<PluginPostRtEvent> data2; 361 CarlaMutex& poolMutex; 362 }; 363 364 private: 365 RtLinkedList<PluginPostRtEvent>::Pool dataPool; 366 RtLinkedList<PluginPostRtEvent> data, dataPendingRT; 367 CarlaMutex dataMutex; 368 CarlaMutex dataPendingMutex; 369 CarlaMutex poolMutex; 370 371 CARLA_DECLARE_NON_COPY_CLASS(PostRtEvents) 372 373 } postRtEvents; 374 375 struct PostUiEvents { 376 CarlaMutex mutex; 377 LinkedList<PluginPostRtEvent> data; 378 379 PostUiEvents() noexcept; 380 ~PostUiEvents() noexcept; 381 void append(const PluginPostRtEvent& event) noexcept; 382 void clear() noexcept; 383 384 CARLA_DECLARE_NON_COPY_STRUCT(PostUiEvents) 385 386 } postUiEvents; 387 388 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 389 struct PostProc { 390 float dryWet; 391 float volume; 392 float balanceLeft; 393 float balanceRight; 394 float panning; 395 396 PostProc() noexcept; 397 398 CARLA_DECLARE_NON_COPY_STRUCT(PostProc) 399 400 } postProc; 401 #endif 402 403 ProtectedData(CarlaEngine* engine, uint idx) noexcept; 404 ~ProtectedData() noexcept; 405 406 // ------------------------------------------------------------------- 407 // Buffer functions 408 409 void clearBuffers() noexcept; 410 411 // ------------------------------------------------------------------- 412 // Post-poned events 413 414 void postponeRtEvent(const PluginPostRtEvent& rtEvent) noexcept; 415 void postponeParameterChangeRtEvent(bool sendCallbackLater, int32_t index, float value) noexcept; 416 void postponeProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept; 417 void postponeMidiProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept; 418 void postponeNoteOnRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note, uint8_t velocity) noexcept; 419 void postponeNoteOffRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note) noexcept; 420 void postponeMidiLearnRtEvent(bool sendCallbackLater, uint32_t parameter, uint8_t cc, uint8_t channel) noexcept; 421 422 // ------------------------------------------------------------------- 423 // Library functions 424 425 static const char* libError(const char* filename) noexcept; 426 427 bool libOpen(const char* filename) noexcept; 428 bool libClose() noexcept; 429 void setCanDeleteLib(bool canDelete) noexcept; 430 431 bool uiLibOpen(const char* filename, bool canDelete) noexcept; 432 bool uiLibClose() noexcept; 433 434 template<typename Func> libSymbolCarlaPlugin::ProtectedData435 Func libSymbol(const char* symbol) const noexcept 436 { 437 return lib_symbol<Func>(lib, symbol); 438 } 439 440 template<typename Func> uiLibSymbolCarlaPlugin::ProtectedData441 Func uiLibSymbol(const char* symbol) const noexcept 442 { 443 return lib_symbol<Func>(uiLib, symbol); 444 } 445 446 // ------------------------------------------------------------------- 447 // Misc 448 449 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 450 void tryTransient() noexcept; 451 #endif 452 void updateParameterValues(CarlaPlugin* plugin, 453 bool sendCallback, bool sendOsc, bool useDefault) noexcept; 454 void updateDefaultParameterValues(CarlaPlugin* plugin) noexcept; 455 456 // ------------------------------------------------------------------- 457 458 #ifdef CARLA_PROPER_CPP11_SUPPORT 459 ProtectedData() = delete; 460 CARLA_DECLARE_NON_COPY_STRUCT(ProtectedData); 461 #endif 462 CARLA_LEAK_DETECTOR(ProtectedData); 463 }; 464 465 CARLA_BACKEND_END_NAMESPACE 466 467 #endif // CARLA_PLUGIN_INTERNAL_HPP_INCLUDED 468