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.

717 lines
19KB

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