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 22KB

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