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.

CarlaEngineInternal.cpp 21KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
6 years ago
10 years ago
6 years ago
6 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2018 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()) {}
  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. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  313. loadingProject(false),
  314. #endif
  315. hints(0x0),
  316. bufferSize(0),
  317. sampleRate(0.0),
  318. aboutToClose(false),
  319. isIdling(0),
  320. curPluginCount(0),
  321. maxPluginNumber(0),
  322. nextPluginId(0),
  323. envMutex(),
  324. lastError(),
  325. name(),
  326. options(),
  327. timeInfo(),
  328. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  329. plugins(nullptr),
  330. #endif
  331. events(),
  332. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  333. graph(engine),
  334. #endif
  335. time(timeInfo, options.transportMode),
  336. nextAction()
  337. {
  338. #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
  339. carla_zeroStructs(plugins, 1);
  340. #endif
  341. }
  342. CarlaEngine::ProtectedData::~ProtectedData() noexcept
  343. {
  344. CARLA_SAFE_ASSERT(curPluginCount == 0);
  345. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  346. CARLA_SAFE_ASSERT(nextPluginId == 0);
  347. CARLA_SAFE_ASSERT(isIdling == 0);
  348. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  349. CARLA_SAFE_ASSERT(plugins == nullptr);
  350. #endif
  351. }
  352. // -----------------------------------------------------------------------
  353. bool CarlaEngine::ProtectedData::init(const char* const clientName)
  354. {
  355. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)");
  356. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  357. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(oscData == nullptr, "Invalid engine internal data (err #2)");
  358. #endif
  359. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)");
  360. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)");
  361. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
  362. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  363. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)");
  364. #endif
  365. aboutToClose = false;
  366. curPluginCount = 0;
  367. nextPluginId = 0;
  368. switch (options.processMode)
  369. {
  370. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  371. maxPluginNumber = MAX_RACK_PLUGINS;
  372. options.forceStereo = true;
  373. break;
  374. case ENGINE_PROCESS_MODE_PATCHBAY:
  375. maxPluginNumber = MAX_PATCHBAY_PLUGINS;
  376. break;
  377. case ENGINE_PROCESS_MODE_BRIDGE:
  378. maxPluginNumber = 1;
  379. break;
  380. default:
  381. maxPluginNumber = MAX_DEFAULT_PLUGINS;
  382. break;
  383. }
  384. switch (options.processMode)
  385. {
  386. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  387. case ENGINE_PROCESS_MODE_PATCHBAY:
  388. case ENGINE_PROCESS_MODE_BRIDGE:
  389. events.in = new EngineEvent[kMaxEngineEventInternalCount];
  390. events.out = new EngineEvent[kMaxEngineEventInternalCount];
  391. carla_zeroStructs(events.in, kMaxEngineEventInternalCount);
  392. carla_zeroStructs(events.out, kMaxEngineEventInternalCount);
  393. break;
  394. default:
  395. break;
  396. }
  397. nextPluginId = maxPluginNumber;
  398. name = clientName;
  399. name.toBasic();
  400. timeInfo.clear();
  401. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  402. osc.init(clientName);
  403. oscData = osc.getControlData();
  404. #endif
  405. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  406. plugins = new EnginePluginData[maxPluginNumber];
  407. carla_zeroStructs(plugins, maxPluginNumber);
  408. #endif
  409. nextAction.clearAndReset();
  410. thread.startThread();
  411. return true;
  412. }
  413. void CarlaEngine::ProtectedData::close()
  414. {
  415. CARLA_SAFE_ASSERT(name.isNotEmpty());
  416. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  417. CARLA_SAFE_ASSERT(plugins != nullptr);
  418. CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber);
  419. #endif
  420. aboutToClose = true;
  421. thread.stopThread(500);
  422. nextAction.clearAndReset();
  423. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  424. osc.close();
  425. oscData = nullptr;
  426. #endif
  427. aboutToClose = false;
  428. curPluginCount = 0;
  429. maxPluginNumber = 0;
  430. nextPluginId = 0;
  431. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  432. if (plugins != nullptr)
  433. {
  434. delete[] plugins;
  435. plugins = nullptr;
  436. }
  437. #endif
  438. events.clear();
  439. name.clear();
  440. }
  441. void CarlaEngine::ProtectedData::initTime(const char* const features)
  442. {
  443. time.init(bufferSize, sampleRate);
  444. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  445. const bool linkEnabled = features != nullptr && std::strstr(features, ":link:") != nullptr;
  446. time.enableLink(linkEnabled);
  447. #else
  448. return;
  449. // unused
  450. (void)features;
  451. #endif
  452. }
  453. // -----------------------------------------------------------------------
  454. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  455. void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept
  456. {
  457. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  458. CARLA_SAFE_ASSERT_RETURN(pluginId < curPluginCount,);
  459. --curPluginCount;
  460. // move all plugins 1 spot backwards
  461. for (uint i=pluginId; i < curPluginCount; ++i)
  462. {
  463. CarlaPlugin* const plugin(plugins[i+1].plugin);
  464. CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
  465. plugin->setId(i);
  466. plugins[i].plugin = plugin;
  467. plugins[i].insPeak[0] = 0.0f;
  468. plugins[i].insPeak[1] = 0.0f;
  469. plugins[i].outsPeak[0] = 0.0f;
  470. plugins[i].outsPeak[1] = 0.0f;
  471. }
  472. const uint id(curPluginCount);
  473. // reset last plugin (now removed)
  474. plugins[id].plugin = nullptr;
  475. plugins[id].insPeak[0] = 0.0f;
  476. plugins[id].insPeak[1] = 0.0f;
  477. plugins[id].outsPeak[0] = 0.0f;
  478. plugins[id].outsPeak[1] = 0.0f;
  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. PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine, const uint32_t frames) noexcept
  536. : pData(engine->pData)
  537. {
  538. pData->time.preProcess(frames);
  539. }
  540. PendingRtEventsRunner::~PendingRtEventsRunner() noexcept
  541. {
  542. pData->doNextPluginAction();
  543. }
  544. // -----------------------------------------------------------------------
  545. // ScopedActionLock
  546. ScopedActionLock::ScopedActionLock(CarlaEngine* const engine,
  547. const EnginePostAction action,
  548. const uint pluginId,
  549. const uint value) noexcept
  550. : pData(engine->pData)
  551. {
  552. CARLA_SAFE_ASSERT_RETURN(action != kEnginePostActionNull,);
  553. {
  554. const CarlaMutexLocker cml(pData->nextAction.mutex);
  555. CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull,);
  556. pData->nextAction.opcode = action;
  557. pData->nextAction.pluginId = pluginId;
  558. pData->nextAction.value = value;
  559. pData->nextAction.needsPost = engine->isRunning();
  560. pData->nextAction.postDone = false;
  561. }
  562. #ifdef BUILD_BRIDGE
  563. #define ACTION_MSG_PREFIX "Bridge: "
  564. #else
  565. #define ACTION_MSG_PREFIX ""
  566. #endif
  567. if (pData->nextAction.needsPost)
  568. {
  569. // block wait for unlock on processing side
  570. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i) - blocking START", pluginId);
  571. bool engineStoppedWhileWaiting = false;
  572. if (! pData->nextAction.postDone)
  573. {
  574. for (int i = 10; --i >= 0;)
  575. {
  576. if (pData->nextAction.sem != nullptr)
  577. {
  578. if (carla_sem_timedwait(*pData->nextAction.sem, 200))
  579. break;
  580. }
  581. else
  582. {
  583. carla_msleep(200);
  584. }
  585. if (! engine->isRunning())
  586. {
  587. engineStoppedWhileWaiting = true;
  588. break;
  589. }
  590. }
  591. }
  592. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i) - blocking DONE", pluginId);
  593. // check if anything went wrong...
  594. if (! pData->nextAction.postDone)
  595. {
  596. bool needsCorrection = false;
  597. {
  598. const CarlaMutexLocker cml(pData->nextAction.mutex);
  599. if (pData->nextAction.opcode != kEnginePostActionNull)
  600. {
  601. needsCorrection = true;
  602. pData->nextAction.needsPost = false;
  603. }
  604. }
  605. if (needsCorrection)
  606. {
  607. pData->doNextPluginAction();
  608. if (! engineStoppedWhileWaiting)
  609. carla_stderr2(ACTION_MSG_PREFIX "Failed to wait for engine, is audio not running?");
  610. }
  611. }
  612. }
  613. else
  614. {
  615. pData->doNextPluginAction();
  616. }
  617. }
  618. ScopedActionLock::~ScopedActionLock() noexcept
  619. {
  620. CARLA_SAFE_ASSERT(pData->nextAction.opcode == kEnginePostActionNull);
  621. }
  622. // -----------------------------------------------------------------------
  623. // ScopedThreadStopper
  624. ScopedThreadStopper::ScopedThreadStopper(CarlaEngine* const e) noexcept
  625. : engine(e),
  626. pData(e->pData)
  627. {
  628. pData->thread.stopThread(500);
  629. }
  630. ScopedThreadStopper::~ScopedThreadStopper() noexcept
  631. {
  632. if (engine->isRunning() && ! pData->aboutToClose)
  633. pData->thread.startThread();
  634. }
  635. // -----------------------------------------------------------------------
  636. // ScopedEngineEnvironmentLocker
  637. ScopedEngineEnvironmentLocker::ScopedEngineEnvironmentLocker(CarlaEngine* const engine) noexcept
  638. : pData(engine->pData)
  639. {
  640. pData->envMutex.lock();
  641. }
  642. ScopedEngineEnvironmentLocker::~ScopedEngineEnvironmentLocker() noexcept
  643. {
  644. pData->envMutex.unlock();
  645. }
  646. // -----------------------------------------------------------------------
  647. CARLA_BACKEND_END_NAMESPACE