1 /* 2 * Carla Plugin Host 3 * Copyright (C) 2011-2020 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_ENGINE_INTERNAL_HPP_INCLUDED 19 #define CARLA_ENGINE_INTERNAL_HPP_INCLUDED 20 21 #include "CarlaEngineThread.hpp" 22 #include "CarlaEngineUtils.hpp" 23 #include "CarlaPlugin.hpp" 24 #include "LinkedList.hpp" 25 26 #ifndef BUILD_BRIDGE 27 # include "CarlaEngineOsc.hpp" 28 # include "hylia/hylia.h" 29 #endif 30 31 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 32 # include "water/processors/AudioProcessorGraph.h" 33 # include "water/containers/Array.h" 34 # include "water/memory/Atomic.h" 35 #endif 36 37 #include <vector> 38 39 // FIXME only use CARLA_PREVENT_HEAP_ALLOCATION for structs 40 // maybe separate macro 41 42 typedef struct _jack_position jack_position_t; 43 struct carla_sem_t; 44 45 CARLA_BACKEND_START_NAMESPACE 46 47 // ----------------------------------------------------------------------- 48 // Engine helper macro, sets lastError and returns false/NULL 49 50 #define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return false; } 51 #define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); setLastError(err); return nullptr; } 52 53 #define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); setLastError(errMsg); return false; } 54 #define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); setLastError(errMsg); return nullptr; } 55 56 // ----------------------------------------------------------------------- 57 // InternalEvents 58 59 struct EngineInternalEvents { 60 EngineEvent* in; 61 EngineEvent* out; 62 63 EngineInternalEvents() noexcept; 64 ~EngineInternalEvents() noexcept; 65 void clear() noexcept; 66 67 CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalEvents) 68 }; 69 70 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 71 // ----------------------------------------------------------------------- 72 // InternalGraph 73 74 struct RackGraph; 75 class PatchbayGraph; 76 77 class EngineInternalGraph 78 { 79 public: 80 EngineInternalGraph(CarlaEngine* engine) noexcept; 81 ~EngineInternalGraph() noexcept; 82 83 void create(uint32_t audioIns, uint32_t audioOuts, uint32_t cvIns, uint32_t cvOuts); 84 void destroy() noexcept; 85 86 void setBufferSize(uint32_t bufferSize); 87 void setSampleRate(double sampleRate); 88 void setOffline(bool offline); 89 isRack() const90 bool isRack() const noexcept 91 { 92 return fIsRack; 93 } 94 isReady() const95 bool isReady() const noexcept 96 { 97 return fIsReady; 98 } 99 getNumAudioOuts() const100 uint32_t getNumAudioOuts() const noexcept 101 { 102 return fNumAudioOuts; 103 } 104 105 RackGraph* getRackGraph() const noexcept; 106 PatchbayGraph* getPatchbayGraph() const noexcept; 107 PatchbayGraph* getPatchbayGraphOrNull() const noexcept; 108 109 void process(CarlaEngine::ProtectedData* data, const float* const* inBuf, float* const* outBuf, uint32_t frames); 110 111 // special direct process with connections already handled, used in JACK and Plugin 112 void processRack(CarlaEngine::ProtectedData* data, const float* inBuf[2], float* outBuf[2], uint32_t frames); 113 114 // used for internal patchbay mode 115 void addPlugin(CarlaPluginPtr plugin); 116 void replacePlugin(CarlaPluginPtr oldPlugin, CarlaPluginPtr newPlugin); 117 void renamePlugin(CarlaPluginPtr plugin, const char* newName); 118 void switchPlugins(CarlaPluginPtr pluginA, CarlaPluginPtr pluginB); 119 void removePlugin(CarlaPluginPtr plugin); 120 void removeAllPlugins(); 121 122 bool isUsingExternalHost() const noexcept; 123 bool isUsingExternalOSC() const noexcept; 124 void setUsingExternalHost(bool usingExternal) noexcept; 125 void setUsingExternalOSC(bool usingExternal) noexcept; 126 127 private: 128 bool fIsRack; 129 uint32_t fNumAudioOuts; 130 volatile bool fIsReady; 131 132 union { 133 RackGraph* fRack; 134 PatchbayGraph* fPatchbay; 135 }; 136 137 CarlaEngine* const kEngine; 138 139 CARLA_PREVENT_HEAP_ALLOCATION 140 CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalGraph) 141 }; 142 #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH 143 144 // ----------------------------------------------------------------------- 145 // InternalTime 146 147 class EngineInternalTime { 148 public: 149 EngineInternalTime(EngineTimeInfo& timeInfo, const EngineTransportMode& transportMode) noexcept; 150 151 void init(uint32_t bufferSize, double sampleRate); 152 void updateAudioValues(uint32_t bufferSize, double sampleRate); 153 154 void enableLink(bool enable); 155 void setBPM(double bpm); 156 void setNeedsReset() noexcept; 157 void pause() noexcept; 158 void relocate(uint64_t frame) noexcept; 159 160 private: 161 double beatsPerBar; 162 double beatsPerMinute; 163 double bufferSize; 164 double sampleRate; 165 bool needsReset; 166 167 uint64_t nextFrame; 168 169 #ifndef BUILD_BRIDGE 170 struct Hylia { 171 bool enabled; 172 hylia_t* instance; 173 hylia_time_info_t timeInfo; 174 175 Hylia(); 176 ~Hylia(); 177 CARLA_DECLARE_NON_COPY_STRUCT(Hylia) 178 } hylia; 179 #endif 180 181 EngineTimeInfo& timeInfo; 182 const EngineTransportMode& transportMode; 183 184 friend class PendingRtEventsRunner; 185 void preProcess(uint32_t numFrames); 186 void fillEngineTimeInfo(uint32_t newFrames) noexcept; 187 188 friend class CarlaEngineJack; 189 void fillJackTimeInfo(jack_position_t* pos, uint32_t newFrames) noexcept; 190 191 CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalTime) 192 }; 193 194 // ----------------------------------------------------------------------- 195 // EngineNextAction 196 197 enum EnginePostAction { 198 kEnginePostActionNull = 0, 199 kEnginePostActionZeroCount, // set curPluginCount to 0 200 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 201 kEnginePostActionRemovePlugin, // remove a plugin 202 kEnginePostActionSwitchPlugins // switch between 2 plugins 203 #endif 204 }; 205 206 struct EngineNextAction { 207 EnginePostAction opcode; 208 uint pluginId; 209 uint value; 210 211 CarlaMutex mutex; 212 213 bool needsPost; 214 volatile bool postDone; 215 carla_sem_t* sem; 216 217 EngineNextAction() noexcept; 218 ~EngineNextAction() noexcept; 219 void clearAndReset() noexcept; 220 221 CARLA_DECLARE_NON_COPY_STRUCT(EngineNextAction) 222 }; 223 224 // ----------------------------------------------------------------------- 225 // EnginePluginData 226 227 struct EnginePluginData { 228 CarlaPluginPtr plugin; 229 float peaks[4]; 230 EnginePluginDataEnginePluginData231 EnginePluginData() 232 : plugin(nullptr), 233 #ifdef CARLA_PROPER_CPP11_SUPPORT 234 peaks{0.0f, 0.0f, 0.0f, 0.0f} {} 235 #else 236 peaks() 237 { 238 carla_zeroStruct(peaks); 239 } 240 #endif 241 }; 242 243 // ----------------------------------------------------------------------- 244 // CarlaEngineProtectedData 245 246 struct CarlaEngine::ProtectedData { 247 CarlaEngineThread thread; 248 249 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) 250 CarlaEngineOsc osc; 251 #endif 252 253 EngineCallbackFunc callback; 254 void* callbackPtr; 255 256 FileCallbackFunc fileCallback; 257 void* fileCallbackPtr; 258 259 bool actionCanceled; 260 261 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 262 bool loadingProject; 263 bool ignoreClientPrefix; // backwards compat only 264 CarlaString currentProjectFilename; 265 CarlaString currentProjectFolder; 266 #endif 267 268 uint32_t bufferSize; 269 double sampleRate; 270 271 bool aboutToClose; // don't re-activate thread if true 272 int isIdling; // don't allow any operations while idling 273 uint curPluginCount; // number of plugins loaded (0...max) 274 uint maxPluginNumber; // number of plugins allowed (0, 16, 99 or 255) 275 uint nextPluginId; // invalid if == maxPluginNumber 276 277 CarlaMutex envMutex; 278 CarlaString lastError; 279 CarlaString name; 280 EngineOptions options; 281 EngineTimeInfo timeInfo; 282 283 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH 284 EnginePluginData plugins[1]; 285 #else 286 EnginePluginData* plugins; 287 uint32_t xruns; 288 float dspLoad; 289 #endif 290 float peaks[4]; 291 std::vector<CarlaPluginPtr> pluginsToDelete; 292 293 EngineInternalEvents events; 294 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH 295 EngineInternalGraph graph; 296 #endif 297 EngineInternalTime time; 298 EngineNextAction nextAction; 299 300 // ------------------------------------------------------------------- 301 302 ProtectedData(CarlaEngine* engine); 303 ~ProtectedData(); 304 305 // ------------------------------------------------------------------- 306 307 bool init(const char* clientName); 308 void close(); 309 310 void initTime(const char* features); 311 312 // ------------------------------------------------------------------- 313 314 void deletePluginsAsNeeded(); 315 316 // ------------------------------------------------------------------- 317 318 void doPluginRemove(uint pluginId) noexcept; 319 void doPluginsSwitch(uint idA, uint idB) noexcept; 320 void doNextPluginAction() noexcept; 321 322 // ------------------------------------------------------------------- 323 324 #ifdef CARLA_PROPER_CPP11_SUPPORT 325 ProtectedData() = delete; 326 CARLA_DECLARE_NON_COPY_STRUCT(ProtectedData) 327 #endif 328 }; 329 330 // ----------------------------------------------------------------------- 331 332 class PendingRtEventsRunner 333 { 334 public: 335 PendingRtEventsRunner(CarlaEngine* engine, 336 uint32_t numFrames, 337 bool calcDSPLoad = false) noexcept; 338 ~PendingRtEventsRunner() noexcept; 339 340 private: 341 CarlaEngine::ProtectedData* const pData; 342 int64_t prevTime; 343 344 CARLA_PREVENT_HEAP_ALLOCATION 345 CARLA_DECLARE_NON_COPY_CLASS(PendingRtEventsRunner) 346 }; 347 348 // ----------------------------------------------------------------------- 349 350 class ScopedActionLock 351 { 352 public: 353 ScopedActionLock(CarlaEngine* engine, EnginePostAction action, uint pluginId, uint value) noexcept; 354 ~ScopedActionLock() noexcept; 355 356 private: 357 CarlaEngine::ProtectedData* const pData; 358 359 CARLA_PREVENT_HEAP_ALLOCATION 360 CARLA_DECLARE_NON_COPY_CLASS(ScopedActionLock) 361 }; 362 363 // ----------------------------------------------------------------------- 364 365 class ScopedThreadStopper 366 { 367 public: 368 ScopedThreadStopper(CarlaEngine* engine) noexcept; 369 ~ScopedThreadStopper() noexcept; 370 371 private: 372 CarlaEngine* const engine; 373 CarlaEngine::ProtectedData* const pData; 374 375 CARLA_PREVENT_HEAP_ALLOCATION 376 CARLA_DECLARE_NON_COPY_CLASS(ScopedThreadStopper) 377 }; 378 379 // ----------------------------------------------------------------------- 380 381 CARLA_BACKEND_END_NAMESPACE 382 383 #endif // CARLA_ENGINE_INTERNAL_HPP_INCLUDED 384