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

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