Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

879 lines
23KB

  1. // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "CarlaEngineInternal.hpp"
  4. #include "CarlaPlugin.hpp"
  5. #include "CarlaSemUtils.hpp"
  6. #include "jackbridge/JackBridge.hpp"
  7. #include <ctime>
  8. #ifdef _MSC_VER
  9. # include <sys/timeb.h>
  10. # include <sys/types.h>
  11. #else
  12. # include <sys/time.h>
  13. #endif
  14. CARLA_BACKEND_START_NAMESPACE
  15. // -----------------------------------------------------------------------
  16. // Engine Internal helper macro, sets lastError and returns false/NULL
  17. #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return false; }
  18. #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return nullptr; }
  19. // -----------------------------------------------------------------------
  20. // InternalEvents
  21. EngineInternalEvents::EngineInternalEvents() noexcept
  22. : in(nullptr),
  23. out(nullptr) {}
  24. EngineInternalEvents::~EngineInternalEvents() noexcept
  25. {
  26. CARLA_SAFE_ASSERT(in == nullptr);
  27. CARLA_SAFE_ASSERT(out == nullptr);
  28. }
  29. void EngineInternalEvents::clear() noexcept
  30. {
  31. if (in != nullptr)
  32. {
  33. delete[] in;
  34. in = nullptr;
  35. }
  36. if (out != nullptr)
  37. {
  38. delete[] out;
  39. out = nullptr;
  40. }
  41. }
  42. // -----------------------------------------------------------------------
  43. // InternalTime
  44. static const double kTicksPerBeat = 1920.0;
  45. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  46. static uint32_t calculate_link_latency(const double bufferSize, const double sampleRate) noexcept
  47. {
  48. CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate), 0);
  49. const long long int latency = llround(1.0e6 * bufferSize / sampleRate);
  50. CARLA_SAFE_ASSERT_RETURN(latency >= 0 && latency < UINT32_MAX, 0);
  51. return static_cast<uint32_t>(latency);
  52. }
  53. #endif
  54. EngineInternalTime::EngineInternalTime(EngineTimeInfo& ti, const EngineTransportMode& tm) noexcept
  55. : beatsPerBar(4.0),
  56. beatsPerMinute(120.0),
  57. bufferSize(0.0),
  58. sampleRate(0.0),
  59. needsReset(false),
  60. nextFrame(0),
  61. #ifndef BUILD_BRIDGE
  62. hylia(),
  63. #endif
  64. timeInfo(ti),
  65. transportMode(tm) {}
  66. void EngineInternalTime::init(const uint32_t bsize, const double srate)
  67. {
  68. bufferSize = bsize;
  69. sampleRate = srate;
  70. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  71. if (hylia.instance != nullptr)
  72. {
  73. hylia_set_beats_per_bar(hylia.instance, beatsPerBar);
  74. hylia_set_beats_per_minute(hylia.instance, beatsPerMinute);
  75. hylia_set_output_latency(hylia.instance, calculate_link_latency(bsize, srate));
  76. if (hylia.enabled)
  77. hylia_enable(hylia.instance, true);
  78. }
  79. #endif
  80. needsReset = true;
  81. }
  82. void EngineInternalTime::updateAudioValues(const uint32_t bsize, const double srate)
  83. {
  84. bufferSize = bsize;
  85. sampleRate = srate;
  86. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  87. if (hylia.instance != nullptr)
  88. hylia_set_output_latency(hylia.instance, calculate_link_latency(bsize, srate));
  89. #endif
  90. needsReset = true;
  91. }
  92. void EngineInternalTime::enableLink(const bool enable)
  93. {
  94. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  95. if (hylia.enabled == enable)
  96. return;
  97. if (hylia.instance != nullptr)
  98. {
  99. hylia.enabled = enable;
  100. hylia_enable(hylia.instance, enable);
  101. }
  102. #else
  103. // unused
  104. (void)enable;
  105. #endif
  106. needsReset = true;
  107. }
  108. void EngineInternalTime::setBPM(const double bpm)
  109. {
  110. beatsPerMinute = bpm;
  111. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  112. if (hylia.instance != nullptr)
  113. hylia_set_beats_per_minute(hylia.instance, bpm);
  114. #endif
  115. }
  116. void EngineInternalTime::setNeedsReset() noexcept
  117. {
  118. needsReset = true;
  119. }
  120. void EngineInternalTime::pause() noexcept
  121. {
  122. timeInfo.playing = false;
  123. nextFrame = timeInfo.frame;
  124. needsReset = true;
  125. }
  126. void EngineInternalTime::relocate(const uint64_t frame) noexcept
  127. {
  128. timeInfo.frame = frame;
  129. nextFrame = frame;
  130. needsReset = true;
  131. }
  132. void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept
  133. {
  134. CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate),);
  135. CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);
  136. double ticktmp;
  137. if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL)
  138. {
  139. timeInfo.usecs = 0;
  140. timeInfo.frame = nextFrame;
  141. }
  142. if (needsReset)
  143. {
  144. timeInfo.bbt.valid = true;
  145. timeInfo.bbt.beatType = 4.0f;
  146. timeInfo.bbt.ticksPerBeat = kTicksPerBeat;
  147. double abs_beat, abs_tick;
  148. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  149. if (hylia.enabled)
  150. {
  151. if (hylia.timeInfo.beat >= 0.0)
  152. {
  153. abs_beat = hylia.timeInfo.beat;
  154. abs_tick = abs_beat * kTicksPerBeat;
  155. }
  156. else
  157. {
  158. abs_beat = 0.0;
  159. abs_tick = 0.0;
  160. timeInfo.playing = false;
  161. }
  162. }
  163. else
  164. #endif
  165. {
  166. const double min = static_cast<double>(timeInfo.frame) / (sampleRate * 60.0);
  167. abs_beat = min * beatsPerMinute;
  168. abs_tick = abs_beat * kTicksPerBeat;
  169. needsReset = false;
  170. }
  171. const double bar = std::floor(abs_beat / beatsPerBar);
  172. const double beat = std::floor(std::fmod(abs_beat, beatsPerBar));
  173. timeInfo.bbt.bar = static_cast<int32_t>(bar) + 1;
  174. timeInfo.bbt.beat = static_cast<int32_t>(beat) + 1;
  175. timeInfo.bbt.barStartTick = ((bar * beatsPerBar) + beat) * kTicksPerBeat;
  176. ticktmp = abs_tick - timeInfo.bbt.barStartTick;
  177. }
  178. else if (timeInfo.playing)
  179. {
  180. ticktmp = timeInfo.bbt.tick + (newFrames * kTicksPerBeat * beatsPerMinute / (sampleRate * 60));
  181. while (ticktmp >= kTicksPerBeat)
  182. {
  183. ticktmp -= kTicksPerBeat;
  184. if (++timeInfo.bbt.beat > beatsPerBar)
  185. {
  186. ++timeInfo.bbt.bar;
  187. timeInfo.bbt.beat = 1;
  188. timeInfo.bbt.barStartTick += beatsPerBar * kTicksPerBeat;
  189. }
  190. }
  191. }
  192. else
  193. {
  194. ticktmp = timeInfo.bbt.tick;
  195. }
  196. timeInfo.bbt.beatsPerBar = static_cast<float>(beatsPerBar);
  197. timeInfo.bbt.beatsPerMinute = beatsPerMinute;
  198. timeInfo.bbt.tick = ticktmp;
  199. if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL && timeInfo.playing)
  200. nextFrame += newFrames;
  201. }
  202. void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint32_t newFrames) noexcept
  203. {
  204. CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate),);
  205. CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);
  206. CARLA_SAFE_ASSERT(transportMode == ENGINE_TRANSPORT_MODE_JACK);
  207. fillEngineTimeInfo(newFrames);
  208. pos->bar = timeInfo.bbt.bar;
  209. pos->beat = timeInfo.bbt.beat;
  210. pos->tick = static_cast<int32_t>(timeInfo.bbt.tick + 0.5);
  211. pos->bar_start_tick = timeInfo.bbt.barStartTick;
  212. pos->beats_per_bar = timeInfo.bbt.beatsPerBar;
  213. pos->beat_type = timeInfo.bbt.beatType;
  214. pos->ticks_per_beat = kTicksPerBeat;
  215. pos->beats_per_minute = beatsPerMinute;
  216. #ifdef JACK_TICK_DOUBLE
  217. pos->tick_double = timeInfo.bbt.tick;
  218. pos->valid = static_cast<jack_position_bits_t>(JackPositionBBT|JackTickDouble);
  219. #else
  220. pos->valid = JackPositionBBT;
  221. #endif
  222. }
  223. void EngineInternalTime::preProcess(const uint32_t numFrames)
  224. {
  225. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  226. if (hylia.enabled)
  227. {
  228. hylia_process(hylia.instance, numFrames, &hylia.timeInfo);
  229. const double new_bpb = hylia.timeInfo.beatsPerBar;
  230. const double new_bpm = hylia.timeInfo.beatsPerMinute;
  231. if (new_bpb >= 1.0 && d_isNotEqual(beatsPerBar, new_bpb))
  232. {
  233. beatsPerBar = new_bpb;
  234. needsReset = true;
  235. }
  236. if (new_bpm > 0.0 && d_isNotEqual(beatsPerMinute, new_bpm))
  237. {
  238. beatsPerMinute = new_bpm;
  239. needsReset = true;
  240. }
  241. }
  242. #endif
  243. if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL)
  244. fillEngineTimeInfo(numFrames);
  245. }
  246. // -----------------------------------------------------------------------
  247. // EngineInternalTime::Hylia
  248. #ifndef BUILD_BRIDGE
  249. EngineInternalTime::Hylia::Hylia()
  250. : enabled(false),
  251. instance(nullptr),
  252. timeInfo()
  253. {
  254. carla_zeroStruct(timeInfo);
  255. # ifdef HAVE_HYLIA
  256. instance = hylia_create();
  257. # endif
  258. }
  259. EngineInternalTime::Hylia::~Hylia()
  260. {
  261. # ifdef HAVE_HYLIA
  262. hylia_cleanup(instance);
  263. # endif
  264. }
  265. #endif
  266. // -----------------------------------------------------------------------
  267. // NextAction
  268. EngineNextAction::EngineNextAction() noexcept
  269. : opcode(kEnginePostActionNull),
  270. pluginId(0),
  271. value(0),
  272. mutex(),
  273. needsPost(false),
  274. postDone(false),
  275. sem(carla_sem_create(false)) {}
  276. EngineNextAction::~EngineNextAction() noexcept
  277. {
  278. CARLA_SAFE_ASSERT(opcode == kEnginePostActionNull);
  279. if (sem != nullptr)
  280. {
  281. carla_sem_destroy(sem);
  282. sem = nullptr;
  283. }
  284. }
  285. void EngineNextAction::clearAndReset() noexcept
  286. {
  287. mutex.lock();
  288. CARLA_SAFE_ASSERT(opcode == kEnginePostActionNull);
  289. opcode = kEnginePostActionNull;
  290. pluginId = 0;
  291. value = 0;
  292. needsPost = false;
  293. postDone = false;
  294. mutex.unlock();
  295. }
  296. // -----------------------------------------------------------------------
  297. // Helper functions
  298. EngineEvent* CarlaEngine::getInternalEventBuffer(const bool isInput) const noexcept
  299. {
  300. return isInput ? pData->events.in : pData->events.out;
  301. }
  302. // -----------------------------------------------------------------------
  303. // CarlaEngine::ProtectedData
  304. CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine)
  305. : runner(engine),
  306. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  307. osc(engine),
  308. #endif
  309. callback(nullptr),
  310. callbackPtr(nullptr),
  311. fileCallback(nullptr),
  312. fileCallbackPtr(nullptr),
  313. actionCanceled(false),
  314. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  315. loadingProject(false),
  316. ignoreClientPrefix(false),
  317. currentProjectFilename(),
  318. currentProjectFolder(),
  319. #endif
  320. bufferSize(0),
  321. sampleRate(0.0),
  322. aboutToClose(false),
  323. isIdling(0),
  324. curPluginCount(0),
  325. maxPluginNumber(0),
  326. nextPluginId(0),
  327. envMutex(),
  328. lastError(),
  329. name(),
  330. options(),
  331. timeInfo(),
  332. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  333. plugins(nullptr),
  334. xruns(0),
  335. dspLoad(0.0f),
  336. #endif
  337. pluginsToDeleteMutex(),
  338. pluginsToDelete(),
  339. events(),
  340. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  341. graph(engine),
  342. #endif
  343. time(timeInfo, options.transportMode),
  344. nextAction()
  345. {
  346. #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
  347. plugins[0].plugin = nullptr;
  348. carla_zeroStructs(plugins[0].peaks, 1);
  349. #endif
  350. }
  351. CarlaEngine::ProtectedData::~ProtectedData()
  352. {
  353. CARLA_SAFE_ASSERT(curPluginCount == 0);
  354. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  355. CARLA_SAFE_ASSERT(nextPluginId == 0);
  356. CARLA_SAFE_ASSERT(isIdling == 0);
  357. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  358. CARLA_SAFE_ASSERT(plugins == nullptr);
  359. #endif
  360. const CarlaMutexLocker cml(pluginsToDeleteMutex);
  361. if (pluginsToDelete.size() != 0)
  362. {
  363. for (std::vector<CarlaPluginPtr>::iterator it = pluginsToDelete.begin(); it != pluginsToDelete.end(); ++it)
  364. {
  365. carla_stderr2("Plugin not yet deleted, name: '%s', usage count: '%u'",
  366. (*it)->getName(), it->use_count());
  367. }
  368. }
  369. pluginsToDelete.clear();
  370. }
  371. // -----------------------------------------------------------------------
  372. bool CarlaEngine::ProtectedData::init(const char* const clientName)
  373. {
  374. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)");
  375. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)");
  376. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)");
  377. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
  378. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  379. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)");
  380. #endif
  381. aboutToClose = false;
  382. curPluginCount = 0;
  383. nextPluginId = 0;
  384. switch (options.processMode)
  385. {
  386. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  387. maxPluginNumber = MAX_RACK_PLUGINS;
  388. options.forceStereo = true;
  389. break;
  390. case ENGINE_PROCESS_MODE_PATCHBAY:
  391. maxPluginNumber = MAX_PATCHBAY_PLUGINS;
  392. break;
  393. case ENGINE_PROCESS_MODE_BRIDGE:
  394. maxPluginNumber = 1;
  395. break;
  396. default:
  397. maxPluginNumber = MAX_DEFAULT_PLUGINS;
  398. break;
  399. }
  400. switch (options.processMode)
  401. {
  402. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  403. case ENGINE_PROCESS_MODE_PATCHBAY:
  404. case ENGINE_PROCESS_MODE_BRIDGE:
  405. events.in = new EngineEvent[kMaxEngineEventInternalCount];
  406. events.out = new EngineEvent[kMaxEngineEventInternalCount];
  407. carla_zeroStructs(events.in, kMaxEngineEventInternalCount);
  408. carla_zeroStructs(events.out, kMaxEngineEventInternalCount);
  409. break;
  410. default:
  411. break;
  412. }
  413. nextPluginId = maxPluginNumber;
  414. name = clientName;
  415. name.toBasic();
  416. timeInfo.clear();
  417. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  418. if (options.oscEnabled)
  419. osc.init(clientName, options.oscPortTCP, options.oscPortUDP);
  420. #endif
  421. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  422. plugins = new EnginePluginData[maxPluginNumber];
  423. xruns = 0;
  424. dspLoad = 0.0f;
  425. #endif
  426. nextAction.clearAndReset();
  427. runner.start();
  428. return true;
  429. }
  430. void CarlaEngine::ProtectedData::close()
  431. {
  432. CARLA_SAFE_ASSERT(name.isNotEmpty());
  433. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  434. CARLA_SAFE_ASSERT(plugins != nullptr);
  435. CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber);
  436. #endif
  437. aboutToClose = true;
  438. runner.stop();
  439. nextAction.clearAndReset();
  440. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  441. osc.close();
  442. #endif
  443. aboutToClose = false;
  444. curPluginCount = 0;
  445. maxPluginNumber = 0;
  446. nextPluginId = 0;
  447. deletePluginsAsNeeded();
  448. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  449. if (plugins != nullptr)
  450. {
  451. delete[] plugins;
  452. plugins = nullptr;
  453. }
  454. #endif
  455. events.clear();
  456. name.clear();
  457. }
  458. void CarlaEngine::ProtectedData::initTime(const char* const features)
  459. {
  460. time.init(bufferSize, sampleRate);
  461. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  462. const bool linkEnabled = features != nullptr && std::strstr(features, ":link:") != nullptr;
  463. time.enableLink(linkEnabled);
  464. #else
  465. return;
  466. // unused
  467. (void)features;
  468. #endif
  469. }
  470. // -----------------------------------------------------------------------
  471. void CarlaEngine::ProtectedData::deletePluginsAsNeeded()
  472. {
  473. std::vector<CarlaPluginPtr> safePluginListToDelete;
  474. if (const size_t size = pluginsToDelete.size())
  475. safePluginListToDelete.reserve(size);
  476. {
  477. const CarlaMutexLocker cml(pluginsToDeleteMutex);
  478. for (std::vector<CarlaPluginPtr>::iterator it = pluginsToDelete.begin(); it != pluginsToDelete.end();)
  479. {
  480. if (it->use_count() == 1)
  481. {
  482. const CarlaPluginPtr plugin = *it;
  483. safePluginListToDelete.push_back(plugin);
  484. pluginsToDelete.erase(it);
  485. }
  486. else
  487. {
  488. ++it;
  489. }
  490. }
  491. }
  492. }
  493. // -----------------------------------------------------------------------
  494. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  495. void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept
  496. {
  497. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  498. CARLA_SAFE_ASSERT_RETURN(pluginId < curPluginCount,);
  499. --curPluginCount;
  500. // move all plugins 1 spot backwards
  501. for (uint i=pluginId; i < curPluginCount; ++i)
  502. {
  503. const CarlaPluginPtr plugin = plugins[i+1].plugin;
  504. CARLA_SAFE_ASSERT_BREAK(plugin.get() != nullptr);
  505. plugin->setId(i);
  506. plugins[i].plugin = plugin;
  507. carla_zeroStruct(plugins[i].peaks);
  508. }
  509. const uint id = curPluginCount;
  510. // reset last plugin (now removed)
  511. plugins[id].plugin.reset();
  512. carla_zeroFloats(plugins[id].peaks, 4);
  513. }
  514. void CarlaEngine::ProtectedData::doPluginsSwitch(const uint idA, const uint idB) noexcept
  515. {
  516. CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
  517. CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
  518. CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
  519. const CarlaPluginPtr pluginA = plugins[idA].plugin;
  520. CARLA_SAFE_ASSERT_RETURN(pluginA.get() != nullptr,);
  521. const CarlaPluginPtr pluginB = plugins[idB].plugin;
  522. CARLA_SAFE_ASSERT_RETURN(pluginB.get() != nullptr,);
  523. pluginA->setId(idB);
  524. plugins[idA].plugin = pluginB;
  525. pluginB->setId(idA);
  526. plugins[idB].plugin = pluginA;
  527. }
  528. #endif
  529. void CarlaEngine::ProtectedData::doNextPluginAction() noexcept
  530. {
  531. if (! nextAction.mutex.tryLock())
  532. return;
  533. const EnginePostAction opcode = nextAction.opcode;
  534. const bool needsPost = nextAction.needsPost;
  535. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  536. const uint pluginId = nextAction.pluginId;
  537. const uint value = nextAction.value;
  538. #endif
  539. nextAction.opcode = kEnginePostActionNull;
  540. nextAction.pluginId = 0;
  541. nextAction.value = 0;
  542. nextAction.needsPost = false;
  543. nextAction.mutex.unlock();
  544. switch (opcode)
  545. {
  546. case kEnginePostActionNull:
  547. break;
  548. case kEnginePostActionZeroCount:
  549. curPluginCount = 0;
  550. break;
  551. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  552. case kEnginePostActionRemovePlugin:
  553. doPluginRemove(pluginId);
  554. break;
  555. case kEnginePostActionSwitchPlugins:
  556. doPluginsSwitch(pluginId, value);
  557. break;
  558. #endif
  559. }
  560. if (needsPost)
  561. {
  562. if (nextAction.sem != nullptr)
  563. carla_sem_post(*nextAction.sem);
  564. nextAction.postDone = true;
  565. }
  566. }
  567. // -----------------------------------------------------------------------
  568. // PendingRtEventsRunner
  569. static int64_t getTimeInMicroseconds() noexcept
  570. {
  571. #if defined(_MSC_VER)
  572. struct _timeb tb;
  573. _ftime_s (&tb);
  574. return ((int64_t) tb.time) * 1000 + tb.millitm;
  575. #elif defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
  576. struct timeval tv;
  577. gettimeofday(&tv, nullptr);
  578. return (tv.tv_sec * 1000000) + tv.tv_usec;
  579. #else
  580. struct timespec ts;
  581. #ifdef CLOCK_MONOTONIC_RAW
  582. clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
  583. #else
  584. clock_gettime(CLOCK_MONOTONIC, &ts);
  585. #endif
  586. return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
  587. #endif
  588. }
  589. PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine,
  590. const uint32_t frames,
  591. const bool calcDSPLoad) noexcept
  592. : pData(engine->pData),
  593. prevTime(calcDSPLoad ? getTimeInMicroseconds() : 0)
  594. {
  595. pData->time.preProcess(frames);
  596. }
  597. PendingRtEventsRunner::~PendingRtEventsRunner() noexcept
  598. {
  599. pData->doNextPluginAction();
  600. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  601. if (prevTime > 0)
  602. {
  603. const int64_t newTime = getTimeInMicroseconds();
  604. if (newTime < prevTime)
  605. return;
  606. const double timeDiff = static_cast<double>(newTime - prevTime) / 1000000.0;
  607. const double maxTime = pData->bufferSize / pData->sampleRate;
  608. const float dspLoad = static_cast<float>(timeDiff / maxTime) * 100.0f;
  609. if (dspLoad > pData->dspLoad)
  610. pData->dspLoad = std::min(100.0f, dspLoad);
  611. else
  612. pData->dspLoad *= static_cast<float>(1.0 - maxTime) + 1e-12f;
  613. }
  614. #endif
  615. }
  616. // -----------------------------------------------------------------------
  617. // ScopedActionLock
  618. ScopedActionLock::ScopedActionLock(CarlaEngine* const engine,
  619. const EnginePostAction action,
  620. const uint pluginId,
  621. const uint value) noexcept
  622. : pData(engine->pData)
  623. {
  624. CARLA_SAFE_ASSERT_RETURN(action != kEnginePostActionNull,);
  625. {
  626. const CarlaMutexLocker cml(pData->nextAction.mutex);
  627. CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull,);
  628. pData->nextAction.opcode = action;
  629. pData->nextAction.pluginId = pluginId;
  630. pData->nextAction.value = value;
  631. pData->nextAction.needsPost = engine->isRunning();
  632. pData->nextAction.postDone = false;
  633. }
  634. #ifdef BUILD_BRIDGE
  635. #define ACTION_MSG_PREFIX "Bridge: "
  636. #else
  637. #define ACTION_MSG_PREFIX ""
  638. #endif
  639. if (pData->nextAction.needsPost)
  640. {
  641. bool engineStoppedWhileWaiting = false;
  642. #ifndef CARLA_OS_WASM
  643. #if defined(DEBUG) || defined(BUILD_BRIDGE)
  644. // block wait for unlock on processing side
  645. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i|%i:%s) - blocking START",
  646. pluginId, action, EnginePostAction2Str(action));
  647. #endif
  648. if (! pData->nextAction.postDone)
  649. {
  650. for (int i = 10; --i >= 0;)
  651. {
  652. if (pData->nextAction.sem != nullptr)
  653. {
  654. if (carla_sem_timedwait(*pData->nextAction.sem, 200))
  655. break;
  656. }
  657. else
  658. {
  659. d_msleep(200);
  660. }
  661. if (! engine->isRunning())
  662. {
  663. engineStoppedWhileWaiting = true;
  664. break;
  665. }
  666. }
  667. }
  668. #if defined(DEBUG) || defined(BUILD_BRIDGE)
  669. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i|%i:%s) - blocking DONE",
  670. pluginId, action, EnginePostAction2Str(action));
  671. #endif
  672. #endif
  673. // check if anything went wrong...
  674. if (! pData->nextAction.postDone)
  675. {
  676. bool needsCorrection = false;
  677. {
  678. const CarlaMutexLocker cml(pData->nextAction.mutex);
  679. if (pData->nextAction.opcode != kEnginePostActionNull)
  680. {
  681. needsCorrection = true;
  682. pData->nextAction.needsPost = false;
  683. }
  684. }
  685. if (needsCorrection)
  686. {
  687. pData->doNextPluginAction();
  688. if (! engineStoppedWhileWaiting)
  689. carla_stderr2(ACTION_MSG_PREFIX "Failed to wait for engine, is audio not running?");
  690. }
  691. }
  692. }
  693. else
  694. {
  695. pData->doNextPluginAction();
  696. }
  697. }
  698. ScopedActionLock::~ScopedActionLock() noexcept
  699. {
  700. CARLA_SAFE_ASSERT(pData->nextAction.opcode == kEnginePostActionNull);
  701. }
  702. // -----------------------------------------------------------------------
  703. // ScopedRunnerStopper
  704. ScopedRunnerStopper::ScopedRunnerStopper(CarlaEngine* const e) noexcept
  705. : engine(e),
  706. pData(e->pData)
  707. {
  708. pData->runner.stop();
  709. }
  710. ScopedRunnerStopper::~ScopedRunnerStopper() noexcept
  711. {
  712. if (engine->isRunning() && ! pData->aboutToClose)
  713. pData->runner.start();
  714. }
  715. // -----------------------------------------------------------------------
  716. // ScopedEngineEnvironmentLocker
  717. ScopedEngineEnvironmentLocker::ScopedEngineEnvironmentLocker(CarlaEngine* const engine) noexcept
  718. : pData(engine->pData)
  719. {
  720. pData->envMutex.lock();
  721. }
  722. ScopedEngineEnvironmentLocker::~ScopedEngineEnvironmentLocker() noexcept
  723. {
  724. pData->envMutex.unlock();
  725. }
  726. // -----------------------------------------------------------------------
  727. CARLA_BACKEND_END_NAMESPACE