Rename a pipe method, add docs
[carla.git] / source / backend / engine / CarlaEngineInternal.cpp
bloba07e406f795bd146424462cb602e1352b23aadde
1 /*
2 * Carla Plugin Host
3 * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
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.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaEngineInternal.hpp"
19 #include "CarlaPlugin.hpp"
20 #include "CarlaSemUtils.hpp"
22 #include "jackbridge/JackBridge.hpp"
24 #include <ctime>
26 #ifdef _MSC_VER
27 # include <sys/timeb.h>
28 # include <sys/types.h>
29 #else
30 # include <sys/time.h>
31 #endif
33 CARLA_BACKEND_START_NAMESPACE
35 // -----------------------------------------------------------------------
36 // Engine Internal helper macro, sets lastError and returns false/NULL
38 #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return false; }
39 #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return nullptr; }
41 // -----------------------------------------------------------------------
42 // InternalEvents
44 EngineInternalEvents::EngineInternalEvents() noexcept
45 : in(nullptr),
46 out(nullptr) {}
48 EngineInternalEvents::~EngineInternalEvents() noexcept
50 CARLA_SAFE_ASSERT(in == nullptr);
51 CARLA_SAFE_ASSERT(out == nullptr);
54 void EngineInternalEvents::clear() noexcept
56 if (in != nullptr)
58 delete[] in;
59 in = nullptr;
62 if (out != nullptr)
64 delete[] out;
65 out = nullptr;
69 // -----------------------------------------------------------------------
70 // InternalTime
72 static const double kTicksPerBeat = 1920.0;
74 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
75 static uint32_t calculate_link_latency(const double bufferSize, const double sampleRate) noexcept
77 CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate), 0);
79 const long long int latency = llround(1.0e6 * bufferSize / sampleRate);
80 CARLA_SAFE_ASSERT_RETURN(latency >= 0 && latency < UINT32_MAX, 0);
82 return static_cast<uint32_t>(latency);
84 #endif
86 EngineInternalTime::EngineInternalTime(EngineTimeInfo& ti, const EngineTransportMode& tm) noexcept
87 : beatsPerBar(4.0),
88 beatsPerMinute(120.0),
89 bufferSize(0.0),
90 sampleRate(0.0),
91 needsReset(false),
92 nextFrame(0),
93 #ifndef BUILD_BRIDGE
94 hylia(),
95 #endif
96 timeInfo(ti),
97 transportMode(tm) {}
99 void EngineInternalTime::init(const uint32_t bsize, const double srate)
101 bufferSize = bsize;
102 sampleRate = srate;
104 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
105 if (hylia.instance != nullptr)
107 hylia_set_beats_per_bar(hylia.instance, beatsPerBar);
108 hylia_set_beats_per_minute(hylia.instance, beatsPerMinute);
109 hylia_set_output_latency(hylia.instance, calculate_link_latency(bsize, srate));
111 if (hylia.enabled)
112 hylia_enable(hylia.instance, true);
114 #endif
116 needsReset = true;
119 void EngineInternalTime::updateAudioValues(const uint32_t bsize, const double srate)
121 bufferSize = bsize;
122 sampleRate = srate;
124 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
125 if (hylia.instance != nullptr)
126 hylia_set_output_latency(hylia.instance, calculate_link_latency(bsize, srate));
127 #endif
129 needsReset = true;
132 void EngineInternalTime::enableLink(const bool enable)
134 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
135 if (hylia.enabled == enable)
136 return;
138 if (hylia.instance != nullptr)
140 hylia.enabled = enable;
141 hylia_enable(hylia.instance, enable);
143 #else
144 // unused
145 (void)enable;
146 #endif
148 needsReset = true;
151 void EngineInternalTime::setBPM(const double bpm)
153 beatsPerMinute = bpm;
155 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
156 if (hylia.instance != nullptr)
157 hylia_set_beats_per_minute(hylia.instance, bpm);
158 #endif
161 void EngineInternalTime::setNeedsReset() noexcept
163 needsReset = true;
166 void EngineInternalTime::pause() noexcept
168 timeInfo.playing = false;
169 nextFrame = timeInfo.frame;
170 needsReset = true;
173 void EngineInternalTime::relocate(const uint64_t frame) noexcept
175 timeInfo.frame = frame;
176 nextFrame = frame;
177 needsReset = true;
180 void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept
182 CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),);
183 CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);
185 double ticktmp;
187 if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL)
189 timeInfo.usecs = 0;
190 timeInfo.frame = nextFrame;
193 if (needsReset)
195 timeInfo.bbt.valid = true;
196 timeInfo.bbt.beatType = 4.0f;
197 timeInfo.bbt.ticksPerBeat = kTicksPerBeat;
199 double abs_beat, abs_tick;
201 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
202 if (hylia.enabled)
204 if (hylia.timeInfo.beat >= 0.0)
206 abs_beat = hylia.timeInfo.beat;
207 abs_tick = abs_beat * kTicksPerBeat;
209 else
211 abs_beat = 0.0;
212 abs_tick = 0.0;
213 timeInfo.playing = false;
216 else
217 #endif
219 const double min = static_cast<double>(timeInfo.frame) / (sampleRate * 60.0);
220 abs_beat = min * beatsPerMinute;
221 abs_tick = abs_beat * kTicksPerBeat;
222 needsReset = false;
225 const double bar = std::floor(abs_beat / beatsPerBar);
226 const double beat = std::floor(std::fmod(abs_beat, beatsPerBar));
228 timeInfo.bbt.bar = static_cast<int32_t>(bar) + 1;
229 timeInfo.bbt.beat = static_cast<int32_t>(beat) + 1;
230 timeInfo.bbt.barStartTick = ((bar * beatsPerBar) + beat) * kTicksPerBeat;
232 ticktmp = abs_tick - timeInfo.bbt.barStartTick;
234 else if (timeInfo.playing)
236 ticktmp = timeInfo.bbt.tick + (newFrames * kTicksPerBeat * beatsPerMinute / (sampleRate * 60));
238 while (ticktmp >= kTicksPerBeat)
240 ticktmp -= kTicksPerBeat;
242 if (++timeInfo.bbt.beat > beatsPerBar)
244 ++timeInfo.bbt.bar;
245 timeInfo.bbt.beat = 1;
246 timeInfo.bbt.barStartTick += beatsPerBar * kTicksPerBeat;
250 else
252 ticktmp = timeInfo.bbt.tick;
255 timeInfo.bbt.beatsPerBar = static_cast<float>(beatsPerBar);
256 timeInfo.bbt.beatsPerMinute = beatsPerMinute;
257 timeInfo.bbt.tick = ticktmp;
259 if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL && timeInfo.playing)
260 nextFrame += newFrames;
263 void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint32_t newFrames) noexcept
265 CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),);
266 CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);
267 CARLA_SAFE_ASSERT(transportMode == ENGINE_TRANSPORT_MODE_JACK);
269 fillEngineTimeInfo(newFrames);
271 pos->bar = timeInfo.bbt.bar;
272 pos->beat = timeInfo.bbt.beat;
273 pos->tick = static_cast<int32_t>(timeInfo.bbt.tick + 0.5);
274 pos->bar_start_tick = timeInfo.bbt.barStartTick;
275 pos->beats_per_bar = timeInfo.bbt.beatsPerBar;
276 pos->beat_type = timeInfo.bbt.beatType;
277 pos->ticks_per_beat = kTicksPerBeat;
278 pos->beats_per_minute = beatsPerMinute;
279 #ifdef JACK_TICK_DOUBLE
280 pos->tick_double = timeInfo.bbt.tick;
281 pos->valid = static_cast<jack_position_bits_t>(JackPositionBBT|JackTickDouble);
282 #else
283 pos->valid = JackPositionBBT;
284 #endif
287 void EngineInternalTime::preProcess(const uint32_t numFrames)
289 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
290 if (hylia.enabled)
292 hylia_process(hylia.instance, numFrames, &hylia.timeInfo);
294 const double new_bpb = hylia.timeInfo.beatsPerBar;
295 const double new_bpm = hylia.timeInfo.beatsPerMinute;
297 if (new_bpb >= 1.0 && carla_isNotEqual(beatsPerBar, new_bpb))
299 beatsPerBar = new_bpb;
300 needsReset = true;
302 if (new_bpm > 0.0 && carla_isNotEqual(beatsPerMinute, new_bpm))
304 beatsPerMinute = new_bpm;
305 needsReset = true;
308 #endif
310 if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL)
311 fillEngineTimeInfo(numFrames);
314 // -----------------------------------------------------------------------
315 // EngineInternalTime::Hylia
317 #ifndef BUILD_BRIDGE
318 EngineInternalTime::Hylia::Hylia()
319 : enabled(false),
320 instance(nullptr),
321 timeInfo()
323 carla_zeroStruct(timeInfo);
325 # ifdef HAVE_HYLIA
326 instance = hylia_create();
327 # endif
330 EngineInternalTime::Hylia::~Hylia()
332 # ifdef HAVE_HYLIA
333 hylia_cleanup(instance);
334 # endif
336 #endif
338 // -----------------------------------------------------------------------
339 // NextAction
341 EngineNextAction::EngineNextAction() noexcept
342 : opcode(kEnginePostActionNull),
343 pluginId(0),
344 value(0),
345 mutex(),
346 needsPost(false),
347 postDone(false),
348 sem(carla_sem_create(false)) {}
350 EngineNextAction::~EngineNextAction() noexcept
352 CARLA_SAFE_ASSERT(opcode == kEnginePostActionNull);
354 if (sem != nullptr)
356 carla_sem_destroy(sem);
357 sem = nullptr;
361 void EngineNextAction::clearAndReset() noexcept
363 mutex.lock();
364 CARLA_SAFE_ASSERT(opcode == kEnginePostActionNull);
366 opcode = kEnginePostActionNull;
367 pluginId = 0;
368 value = 0;
369 needsPost = false;
370 postDone = false;
371 mutex.unlock();
374 // -----------------------------------------------------------------------
375 // Helper functions
377 EngineEvent* CarlaEngine::getInternalEventBuffer(const bool isInput) const noexcept
379 return isInput ? pData->events.in : pData->events.out;
382 // -----------------------------------------------------------------------
383 // CarlaEngine::ProtectedData
385 CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine)
386 : runner(engine),
387 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
388 osc(engine),
389 #endif
390 callback(nullptr),
391 callbackPtr(nullptr),
392 fileCallback(nullptr),
393 fileCallbackPtr(nullptr),
394 actionCanceled(false),
395 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
396 loadingProject(false),
397 ignoreClientPrefix(false),
398 currentProjectFilename(),
399 currentProjectFolder(),
400 #endif
401 bufferSize(0),
402 sampleRate(0.0),
403 aboutToClose(false),
404 isIdling(0),
405 curPluginCount(0),
406 maxPluginNumber(0),
407 nextPluginId(0),
408 envMutex(),
409 lastError(),
410 name(),
411 options(),
412 timeInfo(),
413 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
414 plugins(nullptr),
415 xruns(0),
416 dspLoad(0.0f),
417 #endif
418 pluginsToDeleteMutex(),
419 pluginsToDelete(),
420 events(),
421 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
422 graph(engine),
423 #endif
424 time(timeInfo, options.transportMode),
425 nextAction()
427 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
428 plugins[0].plugin = nullptr;
429 carla_zeroStructs(plugins[0].peaks, 1);
430 #endif
433 CarlaEngine::ProtectedData::~ProtectedData()
435 CARLA_SAFE_ASSERT(curPluginCount == 0);
436 CARLA_SAFE_ASSERT(maxPluginNumber == 0);
437 CARLA_SAFE_ASSERT(nextPluginId == 0);
438 CARLA_SAFE_ASSERT(isIdling == 0);
439 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
440 CARLA_SAFE_ASSERT(plugins == nullptr);
441 #endif
443 const CarlaMutexLocker cml(pluginsToDeleteMutex);
445 if (pluginsToDelete.size() != 0)
447 for (std::vector<CarlaPluginPtr>::iterator it = pluginsToDelete.begin(); it != pluginsToDelete.end(); ++it)
449 carla_stderr2("Plugin not yet deleted, name: '%s', usage count: '%u'",
450 (*it)->getName(), it->use_count());
454 pluginsToDelete.clear();
457 // -----------------------------------------------------------------------
459 bool CarlaEngine::ProtectedData::init(const char* const clientName)
461 CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)");
462 CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)");
463 CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)");
464 CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
465 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
466 CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)");
467 #endif
469 aboutToClose = false;
470 curPluginCount = 0;
471 nextPluginId = 0;
473 switch (options.processMode)
475 case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
476 maxPluginNumber = MAX_RACK_PLUGINS;
477 options.forceStereo = true;
478 break;
479 case ENGINE_PROCESS_MODE_PATCHBAY:
480 maxPluginNumber = MAX_PATCHBAY_PLUGINS;
481 break;
482 case ENGINE_PROCESS_MODE_BRIDGE:
483 maxPluginNumber = 1;
484 break;
485 default:
486 maxPluginNumber = MAX_DEFAULT_PLUGINS;
487 break;
490 switch (options.processMode)
492 case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
493 case ENGINE_PROCESS_MODE_PATCHBAY:
494 case ENGINE_PROCESS_MODE_BRIDGE:
495 events.in = new EngineEvent[kMaxEngineEventInternalCount];
496 events.out = new EngineEvent[kMaxEngineEventInternalCount];
497 carla_zeroStructs(events.in, kMaxEngineEventInternalCount);
498 carla_zeroStructs(events.out, kMaxEngineEventInternalCount);
499 break;
500 default:
501 break;
504 nextPluginId = maxPluginNumber;
506 name = clientName;
507 name.toBasic();
509 timeInfo.clear();
511 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
512 if (options.oscEnabled)
513 osc.init(clientName, options.oscPortTCP, options.oscPortUDP);
514 #endif
516 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
517 plugins = new EnginePluginData[maxPluginNumber];
518 xruns = 0;
519 dspLoad = 0.0f;
520 #endif
522 nextAction.clearAndReset();
523 runner.start();
525 return true;
528 void CarlaEngine::ProtectedData::close()
530 CARLA_SAFE_ASSERT(name.isNotEmpty());
531 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
532 CARLA_SAFE_ASSERT(plugins != nullptr);
533 CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber);
534 #endif
536 aboutToClose = true;
538 runner.stop();
539 nextAction.clearAndReset();
541 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
542 osc.close();
543 #endif
545 aboutToClose = false;
546 curPluginCount = 0;
547 maxPluginNumber = 0;
548 nextPluginId = 0;
550 deletePluginsAsNeeded();
552 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
553 if (plugins != nullptr)
555 delete[] plugins;
556 plugins = nullptr;
558 #endif
560 events.clear();
561 name.clear();
564 void CarlaEngine::ProtectedData::initTime(const char* const features)
566 time.init(bufferSize, sampleRate);
568 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
569 const bool linkEnabled = features != nullptr && std::strstr(features, ":link:") != nullptr;
570 time.enableLink(linkEnabled);
571 #else
572 return;
574 // unused
575 (void)features;
576 #endif
579 // -----------------------------------------------------------------------
581 void CarlaEngine::ProtectedData::deletePluginsAsNeeded()
583 std::vector<CarlaPluginPtr> safePluginListToDelete;
585 if (const size_t size = pluginsToDelete.size())
586 safePluginListToDelete.reserve(size);
589 const CarlaMutexLocker cml(pluginsToDeleteMutex);
591 for (std::vector<CarlaPluginPtr>::iterator it = pluginsToDelete.begin(); it != pluginsToDelete.end();)
593 if (it->use_count() == 1)
595 const CarlaPluginPtr plugin = *it;
596 safePluginListToDelete.push_back(plugin);
597 pluginsToDelete.erase(it);
599 else
601 ++it;
607 // -----------------------------------------------------------------------
609 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
610 void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept
612 CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
613 CARLA_SAFE_ASSERT_RETURN(pluginId < curPluginCount,);
614 --curPluginCount;
616 // move all plugins 1 spot backwards
617 for (uint i=pluginId; i < curPluginCount; ++i)
619 const CarlaPluginPtr plugin = plugins[i+1].plugin;
620 CARLA_SAFE_ASSERT_BREAK(plugin.get() != nullptr);
622 plugin->setId(i);
624 plugins[i].plugin = plugin;
625 carla_zeroStruct(plugins[i].peaks);
628 const uint id = curPluginCount;
630 // reset last plugin (now removed)
631 plugins[id].plugin.reset();
632 carla_zeroFloats(plugins[id].peaks, 4);
635 void CarlaEngine::ProtectedData::doPluginsSwitch(const uint idA, const uint idB) noexcept
637 CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
639 CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
640 CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
642 const CarlaPluginPtr pluginA = plugins[idA].plugin;
643 CARLA_SAFE_ASSERT_RETURN(pluginA.get() != nullptr,);
645 const CarlaPluginPtr pluginB = plugins[idB].plugin;
646 CARLA_SAFE_ASSERT_RETURN(pluginB.get() != nullptr,);
648 pluginA->setId(idB);
649 plugins[idA].plugin = pluginB;
651 pluginB->setId(idA);
652 plugins[idB].plugin = pluginA;
654 #endif
656 void CarlaEngine::ProtectedData::doNextPluginAction() noexcept
658 if (! nextAction.mutex.tryLock())
659 return;
661 const EnginePostAction opcode = nextAction.opcode;
662 const bool needsPost = nextAction.needsPost;
663 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
664 const uint pluginId = nextAction.pluginId;
665 const uint value = nextAction.value;
666 #endif
668 nextAction.opcode = kEnginePostActionNull;
669 nextAction.pluginId = 0;
670 nextAction.value = 0;
671 nextAction.needsPost = false;
673 nextAction.mutex.unlock();
675 switch (opcode)
677 case kEnginePostActionNull:
678 break;
679 case kEnginePostActionZeroCount:
680 curPluginCount = 0;
681 break;
682 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
683 case kEnginePostActionRemovePlugin:
684 doPluginRemove(pluginId);
685 break;
686 case kEnginePostActionSwitchPlugins:
687 doPluginsSwitch(pluginId, value);
688 break;
689 #endif
692 if (needsPost)
694 if (nextAction.sem != nullptr)
695 carla_sem_post(*nextAction.sem);
696 nextAction.postDone = true;
700 // -----------------------------------------------------------------------
701 // PendingRtEventsRunner
703 static int64_t getTimeInMicroseconds() noexcept
705 #if defined(_MSC_VER)
706 struct _timeb tb;
707 _ftime_s (&tb);
708 return ((int64_t) tb.time) * 1000 + tb.millitm;
709 #elif defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
710 struct timeval tv;
711 gettimeofday(&tv, nullptr);
712 return (tv.tv_sec * 1000000) + tv.tv_usec;
713 #else
714 struct timespec ts;
715 #ifdef CLOCK_MONOTONIC_RAW
716 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
717 #else
718 clock_gettime(CLOCK_MONOTONIC, &ts);
719 #endif
720 return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
721 #endif
724 PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine,
725 const uint32_t frames,
726 const bool calcDSPLoad) noexcept
727 : pData(engine->pData),
728 prevTime(calcDSPLoad ? getTimeInMicroseconds() : 0)
730 pData->time.preProcess(frames);
733 PendingRtEventsRunner::~PendingRtEventsRunner() noexcept
735 pData->doNextPluginAction();
737 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
738 if (prevTime > 0)
740 const int64_t newTime = getTimeInMicroseconds();
742 if (newTime < prevTime)
743 return;
745 const double timeDiff = static_cast<double>(newTime - prevTime) / 1000000.0;
746 const double maxTime = pData->bufferSize / pData->sampleRate;
747 const float dspLoad = static_cast<float>(timeDiff / maxTime) * 100.0f;
749 if (dspLoad > pData->dspLoad)
750 pData->dspLoad = std::min(100.0f, dspLoad);
751 else
752 pData->dspLoad *= static_cast<float>(1.0 - maxTime) + 1e-12f;
754 #endif
757 // -----------------------------------------------------------------------
758 // ScopedActionLock
760 ScopedActionLock::ScopedActionLock(CarlaEngine* const engine,
761 const EnginePostAction action,
762 const uint pluginId,
763 const uint value) noexcept
764 : pData(engine->pData)
766 CARLA_SAFE_ASSERT_RETURN(action != kEnginePostActionNull,);
769 const CarlaMutexLocker cml(pData->nextAction.mutex);
771 CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull,);
773 pData->nextAction.opcode = action;
774 pData->nextAction.pluginId = pluginId;
775 pData->nextAction.value = value;
776 pData->nextAction.needsPost = engine->isRunning();
777 pData->nextAction.postDone = false;
780 #ifdef BUILD_BRIDGE
781 #define ACTION_MSG_PREFIX "Bridge: "
782 #else
783 #define ACTION_MSG_PREFIX ""
784 #endif
786 if (pData->nextAction.needsPost)
788 bool engineStoppedWhileWaiting = false;
790 #ifndef CARLA_OS_WASM
791 #if defined(DEBUG) || defined(BUILD_BRIDGE)
792 // block wait for unlock on processing side
793 carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i|%i:%s) - blocking START",
794 pluginId, action, EnginePostAction2Str(action));
795 #endif
797 if (! pData->nextAction.postDone)
799 for (int i = 10; --i >= 0;)
801 if (pData->nextAction.sem != nullptr)
803 if (carla_sem_timedwait(*pData->nextAction.sem, 200))
804 break;
806 else
808 carla_msleep(200);
811 if (! engine->isRunning())
813 engineStoppedWhileWaiting = true;
814 break;
819 #if defined(DEBUG) || defined(BUILD_BRIDGE)
820 carla_stdout(ACTION_MSG_PREFIX "ScopedPluginAction(%i|%i:%s) - blocking DONE",
821 pluginId, action, EnginePostAction2Str(action));
822 #endif
823 #endif
825 // check if anything went wrong...
826 if (! pData->nextAction.postDone)
828 bool needsCorrection = false;
831 const CarlaMutexLocker cml(pData->nextAction.mutex);
833 if (pData->nextAction.opcode != kEnginePostActionNull)
835 needsCorrection = true;
836 pData->nextAction.needsPost = false;
840 if (needsCorrection)
842 pData->doNextPluginAction();
844 if (! engineStoppedWhileWaiting)
845 carla_stderr2(ACTION_MSG_PREFIX "Failed to wait for engine, is audio not running?");
849 else
851 pData->doNextPluginAction();
855 ScopedActionLock::~ScopedActionLock() noexcept
857 CARLA_SAFE_ASSERT(pData->nextAction.opcode == kEnginePostActionNull);
860 // -----------------------------------------------------------------------
861 // ScopedRunnerStopper
863 ScopedRunnerStopper::ScopedRunnerStopper(CarlaEngine* const e) noexcept
864 : engine(e),
865 pData(e->pData)
867 pData->runner.stop();
870 ScopedRunnerStopper::~ScopedRunnerStopper() noexcept
872 if (engine->isRunning() && ! pData->aboutToClose)
873 pData->runner.start();
876 // -----------------------------------------------------------------------
877 // ScopedEngineEnvironmentLocker
879 ScopedEngineEnvironmentLocker::ScopedEngineEnvironmentLocker(CarlaEngine* const engine) noexcept
880 : pData(engine->pData)
882 pData->envMutex.lock();
885 ScopedEngineEnvironmentLocker::~ScopedEngineEnvironmentLocker() noexcept
887 pData->envMutex.unlock();
890 // -----------------------------------------------------------------------
892 CARLA_BACKEND_END_NAMESPACE