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.

827 lines
22KB

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