|
- /*
- * Carla Plugin Host
- * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * For a full copy of the GNU General Public License see the doc/GPL.txt file.
- */
-
- #include "CarlaEngineInternal.hpp"
- #include "CarlaPlugin.hpp"
-
- CARLA_BACKEND_START_NAMESPACE
-
- // -----------------------------------------------------------------------
- // Engine Internal helper macro, sets lastError and returns false/NULL
-
- #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return false; }
- #define CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); lastError = err; return nullptr; }
-
- // -----------------------------------------------------------------------
- // InternalEvents
-
- EngineInternalEvents::EngineInternalEvents() noexcept
- : in(nullptr),
- out(nullptr) {}
-
- EngineInternalEvents::~EngineInternalEvents() noexcept
- {
- CARLA_SAFE_ASSERT(in == nullptr);
- CARLA_SAFE_ASSERT(out == nullptr);
- }
-
- void EngineInternalEvents::clear() noexcept
- {
- if (in != nullptr)
- {
- delete[] in;
- in = nullptr;
- }
-
- if (out != nullptr)
- {
- delete[] out;
- out = nullptr;
- }
- }
-
- // -----------------------------------------------------------------------
- // InternalTime
-
- EngineInternalTime::EngineInternalTime() noexcept
- : playing(false),
- frame(0) {}
-
- // -----------------------------------------------------------------------
- // NextAction
-
- EngineNextAction::EngineNextAction() noexcept
- : opcode(kEnginePostActionNull),
- pluginId(0),
- value(0),
- mutex() {}
-
- EngineNextAction::~EngineNextAction() noexcept
- {
- CARLA_SAFE_ASSERT(opcode == kEnginePostActionNull);
- }
-
- void EngineNextAction::ready() const noexcept
- {
- mutex.lock();
- mutex.unlock();
- }
-
- void EngineNextAction::clearAndReset() noexcept
- {
- mutex.lock();
- opcode = kEnginePostActionNull;
- pluginId = 0;
- value = 0;
- mutex.unlock();
- }
-
- // -----------------------------------------------------------------------
- // CarlaEngine::ProtectedData
-
- CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept
- : thread(engine),
- #ifdef HAVE_LIBLO
- osc(engine),
- oscData(nullptr),
- #endif
- callback(nullptr),
- callbackPtr(nullptr),
- fileCallback(nullptr),
- fileCallbackPtr(nullptr),
- hints(0x0),
- bufferSize(0),
- sampleRate(0.0),
- aboutToClose(false),
- isIdling(0),
- curPluginCount(0),
- maxPluginNumber(0),
- nextPluginId(0),
- envMutex(),
- lastError(),
- name(),
- options(),
- timeInfo(),
- #ifndef BUILD_BRIDGE
- plugins(nullptr),
- #endif
- events(),
- #ifndef BUILD_BRIDGE
- graph(engine),
- #endif
- time(),
- nextAction()
- {
- #ifdef BUILD_BRIDGE
- carla_zeroStructs(plugins, 1);
- #endif
- }
-
- CarlaEngine::ProtectedData::~ProtectedData() noexcept
- {
- CARLA_SAFE_ASSERT(curPluginCount == 0);
- CARLA_SAFE_ASSERT(maxPluginNumber == 0);
- CARLA_SAFE_ASSERT(nextPluginId == 0);
- CARLA_SAFE_ASSERT(isIdling == 0);
- #ifndef BUILD_BRIDGE
- CARLA_SAFE_ASSERT(plugins == nullptr);
- #endif
- }
-
- // -----------------------------------------------------------------------
-
- bool CarlaEngine::ProtectedData::init(const char* const clientName)
- {
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)");
- #ifdef HAVE_LIBLO
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(oscData == nullptr, "Invalid engine internal data (err #2)");
- #endif
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)");
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)");
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name");
- #ifndef BUILD_BRIDGE
- CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)");
- #endif
-
- aboutToClose = false;
- curPluginCount = 0;
- nextPluginId = 0;
-
- switch (options.processMode)
- {
- case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
- maxPluginNumber = MAX_RACK_PLUGINS;
- options.forceStereo = true; // just in case
- break;
- case ENGINE_PROCESS_MODE_PATCHBAY:
- maxPluginNumber = MAX_PATCHBAY_PLUGINS;
- break;
- case ENGINE_PROCESS_MODE_BRIDGE:
- maxPluginNumber = 1;
- break;
- default:
- maxPluginNumber = MAX_DEFAULT_PLUGINS;
- break;
- }
-
- switch (options.processMode)
- {
- case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
- case ENGINE_PROCESS_MODE_PATCHBAY:
- case ENGINE_PROCESS_MODE_BRIDGE:
- events.in = new EngineEvent[kMaxEngineEventInternalCount];
- events.out = new EngineEvent[kMaxEngineEventInternalCount];
- break;
- default:
- break;
- }
-
- nextPluginId = maxPluginNumber;
-
- name = clientName;
- name.toBasic();
-
- timeInfo.clear();
-
- #ifdef HAVE_LIBLO
- osc.init(clientName);
- # ifndef BUILD_BRIDGE
- oscData = osc.getControlData();
- # endif
- #endif
-
- #ifndef BUILD_BRIDGE
- plugins = new EnginePluginData[maxPluginNumber];
- carla_zeroStructs(plugins, maxPluginNumber);
- #endif
-
- nextAction.ready();
- thread.startThread();
-
- return true;
- }
-
- void CarlaEngine::ProtectedData::close()
- {
- CARLA_SAFE_ASSERT(name.isNotEmpty());
- CARLA_SAFE_ASSERT(plugins != nullptr);
- CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber);
- CARLA_SAFE_ASSERT(nextAction.opcode == kEnginePostActionNull);
-
- aboutToClose = true;
-
- thread.stopThread(500);
- nextAction.ready();
-
- #ifdef HAVE_LIBLO
- osc.close();
- oscData = nullptr;
- #endif
-
- aboutToClose = false;
- curPluginCount = 0;
- maxPluginNumber = 0;
- nextPluginId = 0;
-
- #ifndef BUILD_BRIDGE
- if (plugins != nullptr)
- {
- delete[] plugins;
- plugins = nullptr;
- }
- #endif
-
- events.clear();
- name.clear();
- }
-
- // -----------------------------------------------------------------------
-
- #ifndef BUILD_BRIDGE
- void CarlaEngine::ProtectedData::doPluginRemove() noexcept
- {
- CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
- CARLA_SAFE_ASSERT_RETURN(nextAction.pluginId < curPluginCount,);
- --curPluginCount;
-
- // move all plugins 1 spot backwards
- for (uint i=nextAction.pluginId; i < curPluginCount; ++i)
- {
- CarlaPlugin* const plugin(plugins[i+1].plugin);
-
- CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
-
- plugin->setId(i);
-
- plugins[i].plugin = plugin;
- plugins[i].insPeak[0] = 0.0f;
- plugins[i].insPeak[1] = 0.0f;
- plugins[i].outsPeak[0] = 0.0f;
- plugins[i].outsPeak[1] = 0.0f;
- }
-
- const uint id(curPluginCount);
-
- // reset last plugin (now removed)
- plugins[id].plugin = nullptr;
- plugins[id].insPeak[0] = 0.0f;
- plugins[id].insPeak[1] = 0.0f;
- plugins[id].outsPeak[0] = 0.0f;
- plugins[id].outsPeak[1] = 0.0f;
- }
-
- void CarlaEngine::ProtectedData::doPluginsSwitch() noexcept
- {
- CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
-
- const uint idA(nextAction.pluginId);
- const uint idB(nextAction.value);
-
- CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
- CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
- CARLA_SAFE_ASSERT_RETURN(plugins[idA].plugin != nullptr,);
- CARLA_SAFE_ASSERT_RETURN(plugins[idB].plugin != nullptr,);
-
- #if 0
- std::swap(plugins[idA].plugin, plugins[idB].plugin);
- #else
- CarlaPlugin* const tmp(plugins[idA].plugin);
-
- plugins[idA].plugin = plugins[idB].plugin;
- plugins[idB].plugin = tmp;
- #endif
- }
- #endif
-
- void CarlaEngine::ProtectedData::doNextPluginAction(const bool unlock) noexcept
- {
- switch (nextAction.opcode)
- {
- case kEnginePostActionNull:
- break;
- case kEnginePostActionZeroCount:
- curPluginCount = 0;
- break;
- #ifndef BUILD_BRIDGE
- case kEnginePostActionRemovePlugin:
- doPluginRemove();
- break;
- case kEnginePostActionSwitchPlugins:
- doPluginsSwitch();
- break;
- #endif
- }
-
- nextAction.opcode = kEnginePostActionNull;
- nextAction.pluginId = 0;
- nextAction.value = 0;
-
- if (unlock)
- {
- nextAction.mutex.tryLock();
- nextAction.mutex.unlock();
- }
- }
-
- // -----------------------------------------------------------------------
- // PendingRtEventsRunner
-
- PendingRtEventsRunner::PendingRtEventsRunner(CarlaEngine* const engine) noexcept
- : pData(engine->pData) {}
-
- PendingRtEventsRunner::~PendingRtEventsRunner() noexcept
- {
- pData->doNextPluginAction(true);
-
- if (pData->time.playing)
- pData->time.frame += pData->bufferSize;
-
- if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL)
- {
- pData->timeInfo.playing = pData->time.playing;
- pData->timeInfo.frame = pData->time.frame;
- }
- }
-
- // -----------------------------------------------------------------------
- // ScopedActionLock
-
- ScopedActionLock::ScopedActionLock(CarlaEngine* const engine, const EnginePostAction action, const uint pluginId, const uint value, const bool lockWait) noexcept
- : pData(engine->pData)
- {
- CARLA_SAFE_ASSERT_RETURN(action != kEnginePostActionNull,);
-
- pData->nextAction.mutex.lock();
-
- CARLA_SAFE_ASSERT_RETURN(pData->nextAction.opcode == kEnginePostActionNull,);
-
- pData->nextAction.opcode = action;
- pData->nextAction.pluginId = pluginId;
- pData->nextAction.value = value;
-
- if (lockWait)
- {
- // block wait for unlock on processing side
- carla_stdout("ScopedPluginAction(%i) - blocking START", pluginId);
- pData->nextAction.mutex.lock();
- carla_stdout("ScopedPluginAction(%i) - blocking DONE", pluginId);
- }
- else
- {
- pData->doNextPluginAction(false);
- }
- }
-
- ScopedActionLock::~ScopedActionLock() noexcept
- {
- CARLA_SAFE_ASSERT(pData->nextAction.opcode == kEnginePostActionNull);
- pData->nextAction.mutex.tryLock();
- pData->nextAction.mutex.unlock();
- }
-
- // -----------------------------------------------------------------------
- // ScopedThreadStopper
-
- ScopedThreadStopper::ScopedThreadStopper(CarlaEngine* const e) noexcept
- : engine(e),
- pData(e->pData)
- {
- pData->thread.stopThread(500);
- }
-
- ScopedThreadStopper::~ScopedThreadStopper() noexcept
- {
- if (engine->isRunning() && ! pData->aboutToClose)
- pData->thread.startThread();
- }
-
- // -----------------------------------------------------------------------
- // ScopedEngineEnvironmentLocker
-
- ScopedEngineEnvironmentLocker::ScopedEngineEnvironmentLocker(CarlaEngine* const engine) noexcept
- : pData(engine->pData)
- {
- pData->envMutex.lock();
- }
-
- ScopedEngineEnvironmentLocker::~ScopedEngineEnvironmentLocker() noexcept
- {
- pData->envMutex.unlock();
- }
-
- // -----------------------------------------------------------------------
-
- CARLA_BACKEND_END_NAMESPACE
|