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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  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. #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. // CarlaEngine::ProtectedData
  304. CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept
  305. : thread(engine),
  306. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  307. osc(engine),
  308. #endif
  309. callback(nullptr),
  310. callbackPtr(nullptr),
  311. fileCallback(nullptr),
  312. fileCallbackPtr(nullptr),
  313. actionCanceled(false),
  314. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  315. loadingProject(false),
  316. currentProjectFilename(),
  317. #endif
  318. hints(0x0),
  319. bufferSize(0),
  320. sampleRate(0.0),
  321. aboutToClose(false),
  322. isIdling(0),
  323. curPluginCount(0),
  324. maxPluginNumber(0),
  325. nextPluginId(0),
  326. envMutex(),
  327. lastError(),
  328. name(),
  329. options(),
  330. timeInfo(),
  331. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  332. plugins(nullptr),
  333. xruns(0),
  334. dspLoad(0.0f),
  335. #endif
  336. events(),
  337. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  338. graph(engine),
  339. #endif
  340. time(timeInfo, options.transportMode),
  341. nextAction()
  342. {
  343. #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
  344. carla_zeroStructs(plugins, 1);
  345. #endif
  346. }
  347. CarlaEngine::ProtectedData::~ProtectedData() noexcept
  348. {
  349. CARLA_SAFE_ASSERT(curPluginCount == 0);
  350. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  351. CARLA_SAFE_ASSERT(nextPluginId == 0);
  352. CARLA_SAFE_ASSERT(isIdling == 0);
  353. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  354. CARLA_SAFE_ASSERT(plugins == nullptr);
  355. #endif
  356. }
  357. // -----------------------------------------------------------------------
  358. bool CarlaEngine::ProtectedData::init(const char* const clientName)
  359. {
  360. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)");
  361. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)");
  362. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)");
  363. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
  364. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  365. CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)");
  366. #endif
  367. aboutToClose = false;
  368. curPluginCount = 0;
  369. nextPluginId = 0;
  370. switch (options.processMode)
  371. {
  372. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  373. maxPluginNumber = MAX_RACK_PLUGINS;
  374. options.forceStereo = true;
  375. break;
  376. case ENGINE_PROCESS_MODE_PATCHBAY:
  377. maxPluginNumber = MAX_PATCHBAY_PLUGINS;
  378. break;
  379. case ENGINE_PROCESS_MODE_BRIDGE:
  380. maxPluginNumber = 1;
  381. break;
  382. default:
  383. maxPluginNumber = MAX_DEFAULT_PLUGINS;
  384. break;
  385. }
  386. switch (options.processMode)
  387. {
  388. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  389. case ENGINE_PROCESS_MODE_PATCHBAY:
  390. case ENGINE_PROCESS_MODE_BRIDGE:
  391. events.in = new EngineEvent[kMaxEngineEventInternalCount];
  392. events.out = new EngineEvent[kMaxEngineEventInternalCount];
  393. carla_zeroStructs(events.in, kMaxEngineEventInternalCount);
  394. carla_zeroStructs(events.out, kMaxEngineEventInternalCount);
  395. break;
  396. default:
  397. break;
  398. }
  399. nextPluginId = maxPluginNumber;
  400. name = clientName;
  401. name.toBasic();
  402. timeInfo.clear();
  403. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  404. if (options.oscEnabled)
  405. osc.init(clientName, options.oscPortTCP, options.oscPortUDP);
  406. #endif
  407. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  408. plugins = new EnginePluginData[maxPluginNumber];
  409. carla_zeroStructs(plugins, maxPluginNumber);
  410. xruns = 0;
  411. dspLoad = 0.0f;
  412. #endif
  413. nextAction.clearAndReset();
  414. thread.startThread();
  415. return true;
  416. }
  417. void CarlaEngine::ProtectedData::close()
  418. {
  419. CARLA_SAFE_ASSERT(name.isNotEmpty());
  420. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  421. CARLA_SAFE_ASSERT(plugins != nullptr);
  422. CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber);
  423. #endif
  424. aboutToClose = true;
  425. thread.stopThread(500);
  426. nextAction.clearAndReset();
  427. #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
  428. osc.close();
  429. #endif
  430. aboutToClose = false;
  431. curPluginCount = 0;
  432. maxPluginNumber = 0;
  433. nextPluginId = 0;
  434. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  435. if (plugins != nullptr)
  436. {
  437. delete[] plugins;
  438. plugins = nullptr;
  439. }
  440. #endif
  441. events.clear();
  442. name.clear();
  443. }
  444. void CarlaEngine::ProtectedData::initTime(const char* const features)
  445. {
  446. time.init(bufferSize, sampleRate);
  447. #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
  448. const bool linkEnabled = features != nullptr && std::strstr(features, ":link:") != nullptr;
  449. time.enableLink(linkEnabled);
  450. #else
  451. return;
  452. // unused
  453. (void)features;
  454. #endif
  455. }
  456. // -----------------------------------------------------------------------
  457. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  458. void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept
  459. {
  460. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  461. CARLA_SAFE_ASSERT_RETURN(pluginId < curPluginCount,);
  462. --curPluginCount;
  463. // move all plugins 1 spot backwards
  464. for (uint i=pluginId; i < curPluginCount; ++i)
  465. {
  466. CarlaPlugin* const plugin(plugins[i+1].plugin);
  467. CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
  468. plugin->setId(i);
  469. plugins[i].plugin = plugin;
  470. carla_zeroFloats(plugins[i].peaks, 4);
  471. }
  472. const uint id(curPluginCount);
  473. // reset last plugin (now removed)
  474. plugins[id].plugin = nullptr;
  475. carla_zeroFloats(plugins[id].peaks, 4);
  476. }
  477. void CarlaEngine::ProtectedData::doPluginsSwitch(const uint idA, const uint idB) noexcept
  478. {
  479. CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
  480. CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
  481. CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
  482. CarlaPlugin* const pluginA(plugins[idA].plugin);
  483. CARLA_SAFE_ASSERT_RETURN(pluginA != nullptr,);
  484. CarlaPlugin* const pluginB(plugins[idB].plugin);
  485. CARLA_SAFE_ASSERT_RETURN(pluginB != nullptr,);
  486. pluginA->setId(idB);
  487. plugins[idA].plugin = pluginB;
  488. pluginB->setId(idA);
  489. plugins[idB].plugin = pluginA;
  490. }
  491. #endif
  492. void CarlaEngine::ProtectedData::doNextPluginAction() noexcept
  493. {
  494. if (! nextAction.mutex.tryLock())
  495. return;
  496. const EnginePostAction opcode = nextAction.opcode;
  497. const bool needsPost = nextAction.needsPost;
  498. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  499. const uint pluginId = nextAction.pluginId;
  500. const uint value = nextAction.value;
  501. #endif
  502. nextAction.opcode = kEnginePostActionNull;
  503. nextAction.pluginId = 0;
  504. nextAction.value = 0;
  505. nextAction.needsPost = false;
  506. nextAction.mutex.unlock();
  507. switch (opcode)
  508. {
  509. case kEnginePostActionNull:
  510. break;
  511. case kEnginePostActionZeroCount:
  512. curPluginCount = 0;
  513. break;
  514. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  515. case kEnginePostActionRemovePlugin:
  516. doPluginRemove(pluginId);
  517. break;
  518. case kEnginePostActionSwitchPlugins:
  519. doPluginsSwitch(pluginId, value);
  520. break;
  521. #endif
  522. }
  523. if (needsPost)
  524. {
  525. if (nextAction.sem != nullptr)
  526. carla_sem_post(*nextAction.sem);
  527. nextAction.postDone = true;
  528. }
  529. }
  530. // -----------------------------------------------------------------------
  531. // PendingRtEventsRunner
  532. static int64_t getTimeInMicroseconds() noexcept
  533. {
  534. #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
  535. struct timeval tv;
  536. gettimeofday(&tv, nullptr);
  537. return (tv.tv_sec * 1000000) + tv.tv_usec;
  538. #else
  539. struct timespec ts;
  540. # ifdef CLOCK_MONOTONIC_RAW
  541. clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
  542. # else
  543. clock_gettime(CLOCK_MONOTONIC, &ts);
  544. # endif
  545. return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
  546. #endif
  547. }
  548. PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine,
  549. const uint32_t frames,
  550. const bool calcDSPLoad) noexcept
  551. : pData(engine->pData),
  552. prevTime(calcDSPLoad ? getTimeInMicroseconds() : 0)
  553. {
  554. pData->time.preProcess(frames);
  555. }
  556. PendingRtEventsRunner::~PendingRtEventsRunner() noexcept
  557. {
  558. pData->doNextPluginAction();
  559. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  560. if (prevTime > 0)
  561. {
  562. const int64_t newTime = getTimeInMicroseconds();
  563. if (newTime < prevTime)
  564. return;
  565. const double timeDiff = static_cast<double>(newTime - prevTime) / 1000000.0;
  566. const double maxTime = pData->bufferSize / pData->sampleRate;
  567. const float dspLoad = static_cast<float>(timeDiff / maxTime) * 100.0f;
  568. if (dspLoad > pData->dspLoad)
  569. pData->dspLoad = std::min(100.0f, dspLoad);
  570. else
  571. pData->dspLoad *= static_cast<float>(1.0 - maxTime) + 1e-12f;
  572. }
  573. #endif
  574. }
  575. // -----------------------------------------------------------------------
  576. // ScopedActionLock
  577. ScopedActionLock::ScopedActionLock(CarlaEngine* const engine,
  578. const EnginePostAction action,
  579. const uint pluginId,
  580. const uint value) noexcept
  581. : pData(engine->pData)
  582. {
  583. CARLA_SAFE_ASSERT_RETURN(action != kEnginePostActionNull,);
  584. {
  585. const CarlaMutexLocker cml(pData->nextAction.mutex);
  586. CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull,);
  587. pData->nextAction.opcode = action;
  588. pData->nextAction.pluginId = pluginId;
  589. pData->nextAction.value = value;
  590. pData->nextAction.needsPost = engine->isRunning();
  591. pData->nextAction.postDone = false;
  592. }
  593. #ifdef BUILD_BRIDGE
  594. #define ACTION_MSG_PREFIX "Bridge: "
  595. #else
  596. #define ACTION_MSG_PREFIX ""
  597. #endif
  598. if (pData->nextAction.needsPost)
  599. {
  600. #if defined(DEBUG) || defined(BUILD_BRIDGE)
  601. // block wait for unlock on processing side
  602. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i) - blocking START", pluginId);
  603. #endif
  604. bool engineStoppedWhileWaiting = false;
  605. if (! pData->nextAction.postDone)
  606. {
  607. for (int i = 10; --i >= 0;)
  608. {
  609. if (pData->nextAction.sem != nullptr)
  610. {
  611. if (carla_sem_timedwait(*pData->nextAction.sem, 200))
  612. break;
  613. }
  614. else
  615. {
  616. carla_msleep(200);
  617. }
  618. if (! engine->isRunning())
  619. {
  620. engineStoppedWhileWaiting = true;
  621. break;
  622. }
  623. }
  624. }
  625. #if defined(DEBUG) || defined(BUILD_BRIDGE)
  626. carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i) - blocking DONE", pluginId);
  627. #endif
  628. // check if anything went wrong...
  629. if (! pData->nextAction.postDone)
  630. {
  631. bool needsCorrection = false;
  632. {
  633. const CarlaMutexLocker cml(pData->nextAction.mutex);
  634. if (pData->nextAction.opcode != kEnginePostActionNull)
  635. {
  636. needsCorrection = true;
  637. pData->nextAction.needsPost = false;
  638. }
  639. }
  640. if (needsCorrection)
  641. {
  642. pData->doNextPluginAction();
  643. if (! engineStoppedWhileWaiting)
  644. carla_stderr2(ACTION_MSG_PREFIX "Failed to wait for engine, is audio not running?");
  645. }
  646. }
  647. }
  648. else
  649. {
  650. pData->doNextPluginAction();
  651. }
  652. }
  653. ScopedActionLock::~ScopedActionLock() noexcept
  654. {
  655. CARLA_SAFE_ASSERT(pData->nextAction.opcode == kEnginePostActionNull);
  656. }
  657. // -----------------------------------------------------------------------
  658. // ScopedThreadStopper
  659. ScopedThreadStopper::ScopedThreadStopper(CarlaEngine* const e) noexcept
  660. : engine(e),
  661. pData(e->pData)
  662. {
  663. pData->thread.stopThread(500);
  664. }
  665. ScopedThreadStopper::~ScopedThreadStopper() noexcept
  666. {
  667. if (engine->isRunning() && ! pData->aboutToClose)
  668. pData->thread.startThread();
  669. }
  670. // -----------------------------------------------------------------------
  671. // ScopedEngineEnvironmentLocker
  672. ScopedEngineEnvironmentLocker::ScopedEngineEnvironmentLocker(CarlaEngine* const engine) noexcept
  673. : pData(engine->pData)
  674. {
  675. pData->envMutex.lock();
  676. }
  677. ScopedEngineEnvironmentLocker::~ScopedEngineEnvironmentLocker() noexcept
  678. {
  679. pData->envMutex.unlock();
  680. }
  681. // -----------------------------------------------------------------------
  682. CARLA_BACKEND_END_NAMESPACE