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

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