|  | @@ -33,7 +33,6 @@ | 
														
													
														
															
																|  |  | #include <atomic> |  |  | #include <atomic> | 
														
													
														
															
																|  |  | #include <tuple> |  |  | #include <tuple> | 
														
													
														
															
																|  |  | #include <pmmintrin.h> |  |  | #include <pmmintrin.h> | 
														
													
														
															
																|  |  | #include <pthread.h> |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | #include <engine/Engine.hpp> |  |  | #include <engine/Engine.hpp> | 
														
													
														
															
																|  |  | #include <settings.hpp> |  |  | #include <settings.hpp> | 
														
													
												
													
														
															
																|  | @@ -41,6 +40,7 @@ | 
														
													
														
															
																|  |  | #include <random.hpp> |  |  | #include <random.hpp> | 
														
													
														
															
																|  |  | #include <patch.hpp> |  |  | #include <patch.hpp> | 
														
													
														
															
																|  |  | #include <plugin.hpp> |  |  | #include <plugin.hpp> | 
														
													
														
															
																|  |  |  |  |  | #include <mutex.hpp> | 
														
													
														
															
																|  |  | #include <helpers.hpp> |  |  | #include <helpers.hpp> | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | #ifdef NDEBUG |  |  | #ifdef NDEBUG | 
														
													
												
													
														
															
																|  | @@ -53,55 +53,6 @@ namespace rack { | 
														
													
														
															
																|  |  | namespace engine { |  |  | namespace engine { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | /** Allows multiple "reader" threads to obtain a lock simultaneously, but only one "writer" thread. |  |  |  | 
														
													
														
															
																|  |  | This implementation is currently just a wrapper for pthreads, which works on Linux/Mac/. |  |  |  | 
														
													
														
															
																|  |  | This is available in C++17 as std::shared_mutex, but unfortunately we're using C++11. |  |  |  | 
														
													
														
															
																|  |  | */ |  |  |  | 
														
													
														
															
																|  |  | struct ReadWriteMutex { |  |  |  | 
														
													
														
															
																|  |  | pthread_rwlock_t rwlock; |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | ReadWriteMutex() { |  |  |  | 
														
													
														
															
																|  |  | if (pthread_rwlock_init(&rwlock, nullptr)) |  |  |  | 
														
													
														
															
																|  |  | throw Exception("pthread_rwlock_init failed"); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | ~ReadWriteMutex() { |  |  |  | 
														
													
														
															
																|  |  | pthread_rwlock_destroy(&rwlock); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | void lockReader() { |  |  |  | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_rdlock(&rwlock) == 0,); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | void unlockReader() { |  |  |  | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_unlock(&rwlock) == 0,); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | void lockWriter() { |  |  |  | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_wrlock(&rwlock) == 0,); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | void unlockWriter() { |  |  |  | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(pthread_rwlock_unlock(&rwlock) == 0,); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | }; |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | struct ReadLock { |  |  |  | 
														
													
														
															
																|  |  | ReadWriteMutex& m; |  |  |  | 
														
													
														
															
																|  |  | ReadLock(ReadWriteMutex& m) : m(m) { |  |  |  | 
														
													
														
															
																|  |  | m.lockReader(); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | ~ReadLock() { |  |  |  | 
														
													
														
															
																|  |  | m.unlockReader(); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | }; |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | struct WriteLock { |  |  |  | 
														
													
														
															
																|  |  | ReadWriteMutex& m; |  |  |  | 
														
													
														
															
																|  |  | WriteLock(ReadWriteMutex& m) : m(m) { |  |  |  | 
														
													
														
															
																|  |  | m.lockWriter(); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | ~WriteLock() { |  |  |  | 
														
													
														
															
																|  |  | m.unlockWriter(); |  |  |  | 
														
													
														
															
																|  |  | } |  |  |  | 
														
													
														
															
																|  |  | }; |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | 
 |  |  |  | 
														
													
														
															
																|  |  | struct Engine::Internal { |  |  | struct Engine::Internal { | 
														
													
														
															
																|  |  | std::vector<Module*> modules; |  |  | std::vector<Module*> modules; | 
														
													
														
															
																|  |  | std::vector<Cable*> cables; |  |  | std::vector<Cable*> cables; | 
														
													
												
													
														
															
																|  | @@ -139,7 +90,7 @@ struct Engine::Internal { | 
														
													
														
															
																|  |  | Writers lock when mutating the engine's state or stepping the block. |  |  | Writers lock when mutating the engine's state or stepping the block. | 
														
													
														
															
																|  |  | Readers lock when using the engine's state. |  |  | Readers lock when using the engine's state. | 
														
													
														
															
																|  |  | */ |  |  | */ | 
														
													
														
															
																|  |  | ReadWriteMutex mutex; |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedMutex mutex; | 
														
													
														
															
																|  |  | }; |  |  | }; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -329,7 +280,7 @@ Engine::~Engine() { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::clear() { |  |  | void Engine::clear() { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | clear_NoLock(); |  |  | clear_NoLock(); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -358,7 +309,7 @@ void Engine::stepBlock(int frames) { | 
														
													
														
															
																|  |  | // Start timer before locking |  |  | // Start timer before locking | 
														
													
														
															
																|  |  | double startTime = system::getTime(); |  |  | double startTime = system::getTime(); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | // Configure thread |  |  | // Configure thread | 
														
													
														
															
																|  |  | random::init(); |  |  | random::init(); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -420,7 +371,7 @@ float Engine::getSampleRate() { | 
														
													
														
															
																|  |  | void Engine::setSampleRate(float sampleRate) { |  |  | void Engine::setSampleRate(float sampleRate) { | 
														
													
														
															
																|  |  | if (sampleRate == internal->sampleRate) |  |  | if (sampleRate == internal->sampleRate) | 
														
													
														
															
																|  |  | return; |  |  | return; | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | internal->sampleRate = sampleRate; |  |  | internal->sampleRate = sampleRate; | 
														
													
														
															
																|  |  | internal->sampleTime = 1.f / sampleRate; |  |  | internal->sampleTime = 1.f / sampleRate; | 
														
													
												
													
														
															
																|  | @@ -498,7 +449,7 @@ size_t Engine::getNumModules() { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { |  |  | size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | size_t i = 0; |  |  | size_t i = 0; | 
														
													
														
															
																|  |  | for (Module* m : internal->modules) { |  |  | for (Module* m : internal->modules) { | 
														
													
														
															
																|  |  | if (i >= len) |  |  | if (i >= len) | 
														
													
												
													
														
															
																|  | @@ -511,7 +462,7 @@ size_t Engine::getModuleIds(int64_t* moduleIds, size_t len) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | std::vector<int64_t> Engine::getModuleIds() { |  |  | std::vector<int64_t> Engine::getModuleIds() { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | std::vector<int64_t> moduleIds; |  |  | std::vector<int64_t> moduleIds; | 
														
													
														
															
																|  |  | moduleIds.reserve(internal->modules.size()); |  |  | moduleIds.reserve(internal->modules.size()); | 
														
													
														
															
																|  |  | for (Module* m : internal->modules) { |  |  | for (Module* m : internal->modules) { | 
														
													
												
													
														
															
																|  | @@ -522,7 +473,7 @@ std::vector<int64_t> Engine::getModuleIds() { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::addModule(Module* module) { |  |  | void Engine::addModule(Module* module) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); | 
														
													
														
															
																|  |  | // Check that the module is not already added |  |  | // Check that the module is not already added | 
														
													
														
															
																|  |  | auto it = std::find(internal->modules.begin(), internal->modules.end(), module); |  |  | auto it = std::find(internal->modules.begin(), internal->modules.end(), module); | 
														
													
												
													
														
															
																|  | @@ -552,7 +503,7 @@ void Engine::addModule(Module* module) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::removeModule(Module* module) { |  |  | void Engine::removeModule(Module* module) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | removeModule_NoLock(module); |  |  | removeModule_NoLock(module); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -606,7 +557,7 @@ void Engine::removeModule_NoLock(Module* module) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | bool Engine::hasModule(Module* module) { |  |  | bool Engine::hasModule(Module* module) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. |  |  | // TODO Performance could be improved by searching modulesCache, but more testing would be needed to make sure it's always valid. | 
														
													
														
															
																|  |  | auto it = std::find(internal->modules.begin(), internal->modules.end(), module); |  |  | auto it = std::find(internal->modules.begin(), internal->modules.end(), module); | 
														
													
														
															
																|  |  | return it != internal->modules.end(); |  |  | return it != internal->modules.end(); | 
														
													
												
													
														
															
																|  | @@ -614,7 +565,7 @@ bool Engine::hasModule(Module* module) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | Module* Engine::getModule(int64_t moduleId) { |  |  | Module* Engine::getModule(int64_t moduleId) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | return getModule_NoLock(moduleId); |  |  | return getModule_NoLock(moduleId); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -628,7 +579,7 @@ Module* Engine::getModule_NoLock(int64_t moduleId) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::resetModule(Module* module) { |  |  | void Engine::resetModule(Module* module) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | Module::ResetEvent eReset; |  |  | Module::ResetEvent eReset; | 
														
													
												
													
														
															
																|  | @@ -637,7 +588,7 @@ void Engine::resetModule(Module* module) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::randomizeModule(Module* module) { |  |  | void Engine::randomizeModule(Module* module) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(module,); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | Module::RandomizeEvent eRandomize; |  |  | Module::RandomizeEvent eRandomize; | 
														
													
												
													
														
															
																|  | @@ -650,7 +601,7 @@ void Engine::bypassModule(Module* module, bool bypassed) { | 
														
													
														
															
																|  |  | if (module->isBypassed() == bypassed) |  |  | if (module->isBypassed() == bypassed) | 
														
													
														
															
																|  |  | return; |  |  | return; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | // Clear outputs and set to 1 channel |  |  | // Clear outputs and set to 1 channel | 
														
													
														
															
																|  |  | for (Output& output : module->outputs) { |  |  | for (Output& output : module->outputs) { | 
														
													
												
													
														
															
																|  | @@ -673,26 +624,26 @@ void Engine::bypassModule(Module* module, bool bypassed) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | json_t* Engine::moduleToJson(Module* module) { |  |  | json_t* Engine::moduleToJson(Module* module) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | return module->toJson(); |  |  | return module->toJson(); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::moduleFromJson(Module* module, json_t* rootJ) { |  |  | void Engine::moduleFromJson(Module* module, json_t* rootJ) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | module->fromJson(rootJ); |  |  | module->fromJson(rootJ); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::prepareSaveModule(Module* module) { |  |  | void Engine::prepareSaveModule(Module* module) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | Module::SaveEvent e; |  |  | Module::SaveEvent e; | 
														
													
														
															
																|  |  | module->onSave(e); |  |  | module->onSave(e); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::prepareSave() { |  |  | void Engine::prepareSave() { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | for (Module* module : internal->modules) { |  |  | for (Module* module : internal->modules) { | 
														
													
														
															
																|  |  | Module::SaveEvent e; |  |  | Module::SaveEvent e; | 
														
													
														
															
																|  |  | module->onSave(e); |  |  | module->onSave(e); | 
														
													
												
													
														
															
																|  | @@ -706,7 +657,7 @@ size_t Engine::getNumCables() { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | size_t Engine::getCableIds(int64_t* cableIds, size_t len) { |  |  | size_t Engine::getCableIds(int64_t* cableIds, size_t len) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | size_t i = 0; |  |  | size_t i = 0; | 
														
													
														
															
																|  |  | for (Cable* c : internal->cables) { |  |  | for (Cable* c : internal->cables) { | 
														
													
														
															
																|  |  | if (i >= len) |  |  | if (i >= len) | 
														
													
												
													
														
															
																|  | @@ -719,7 +670,7 @@ size_t Engine::getCableIds(int64_t* cableIds, size_t len) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | std::vector<int64_t> Engine::getCableIds() { |  |  | std::vector<int64_t> Engine::getCableIds() { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | std::vector<int64_t> cableIds; |  |  | std::vector<int64_t> cableIds; | 
														
													
														
															
																|  |  | cableIds.reserve(internal->cables.size()); |  |  | cableIds.reserve(internal->cables.size()); | 
														
													
														
															
																|  |  | for (Cable* c : internal->cables) { |  |  | for (Cable* c : internal->cables) { | 
														
													
												
													
														
															
																|  | @@ -730,7 +681,7 @@ std::vector<int64_t> Engine::getCableIds() { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::addCable(Cable* cable) { |  |  | void Engine::addCable(Cable* cable) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(cable,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(cable,); | 
														
													
														
															
																|  |  | // Check cable properties |  |  | // Check cable properties | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(cable->inputModule,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(cable->inputModule,); | 
														
													
												
													
														
															
																|  | @@ -775,7 +726,7 @@ void Engine::addCable(Cable* cable) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::removeCable(Cable* cable) { |  |  | void Engine::removeCable(Cable* cable) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | removeCable_NoLock(cable); |  |  | removeCable_NoLock(cable); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -816,7 +767,7 @@ void Engine::removeCable_NoLock(Cable* cable) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | bool Engine::hasCable(Cable* cable) { |  |  | bool Engine::hasCable(Cable* cable) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | // TODO Performance could be improved by searching cablesCache, but more testing would be needed to make sure it's always valid. |  |  | // TODO Performance could be improved by searching cablesCache, but more testing would be needed to make sure it's always valid. | 
														
													
														
															
																|  |  | auto it = std::find(internal->cables.begin(), internal->cables.end(), cable); |  |  | auto it = std::find(internal->cables.begin(), internal->cables.end(), cable); | 
														
													
														
															
																|  |  | return it != internal->cables.end(); |  |  | return it != internal->cables.end(); | 
														
													
												
													
														
															
																|  | @@ -824,7 +775,7 @@ bool Engine::hasCable(Cable* cable) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | Cable* Engine::getCable(int64_t cableId) { |  |  | Cable* Engine::getCable(int64_t cableId) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | auto it = internal->cablesCache.find(cableId); |  |  | auto it = internal->cablesCache.find(cableId); | 
														
													
														
															
																|  |  | if (it == internal->cablesCache.end()) |  |  | if (it == internal->cablesCache.end()) | 
														
													
														
															
																|  |  | return NULL; |  |  | return NULL; | 
														
													
												
													
														
															
																|  | @@ -867,7 +818,7 @@ float Engine::getParamSmoothValue(Module* module, int paramId) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::addParamHandle(ParamHandle* paramHandle) { |  |  | void Engine::addParamHandle(ParamHandle* paramHandle) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | // New ParamHandles must be blank. |  |  | // New ParamHandles must be blank. | 
														
													
														
															
																|  |  | // This means we don't have to refresh the cache. |  |  | // This means we don't have to refresh the cache. | 
														
													
														
															
																|  |  | DISTRHO_SAFE_ASSERT_RETURN(paramHandle->moduleId < 0,); |  |  | DISTRHO_SAFE_ASSERT_RETURN(paramHandle->moduleId < 0,); | 
														
													
												
													
														
															
																|  | @@ -883,7 +834,7 @@ void Engine::addParamHandle(ParamHandle* paramHandle) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::removeParamHandle(ParamHandle* paramHandle) { |  |  | void Engine::removeParamHandle(ParamHandle* paramHandle) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | removeParamHandle_NoLock(paramHandle); |  |  | removeParamHandle_NoLock(paramHandle); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -901,7 +852,7 @@ void Engine::removeParamHandle_NoLock(ParamHandle* paramHandle) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | ParamHandle* Engine::getParamHandle(int64_t moduleId, int paramId) { |  |  | ParamHandle* Engine::getParamHandle(int64_t moduleId, int paramId) { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | return getParamHandle_NoLock(moduleId, paramId); |  |  | return getParamHandle_NoLock(moduleId, paramId); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -920,7 +871,7 @@ ParamHandle* Engine::getParamHandle(Module* module, int paramId) { | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | void Engine::updateParamHandle(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { |  |  | void Engine::updateParamHandle(ParamHandle* paramHandle, int64_t moduleId, int paramId, bool overwrite) { | 
														
													
														
															
																|  |  | WriteLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | std::lock_guard<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | updateParamHandle_NoLock(paramHandle, moduleId, paramId, overwrite); |  |  | updateParamHandle_NoLock(paramHandle, moduleId, paramId, overwrite); | 
														
													
														
															
																|  |  | } |  |  | } | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
												
													
														
															
																|  | @@ -963,7 +914,7 @@ void Engine::updateParamHandle_NoLock(ParamHandle* paramHandle, int64_t moduleId | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | json_t* Engine::toJson() { |  |  | json_t* Engine::toJson() { | 
														
													
														
															
																|  |  | ReadLock lock(internal->mutex); |  |  |  | 
														
													
														
															
																|  |  |  |  |  | SharedLock<SharedMutex> lock(internal->mutex); | 
														
													
														
															
																|  |  | json_t* rootJ = json_object(); |  |  | json_t* rootJ = json_object(); | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  | // modules |  |  | // modules | 
														
													
												
													
														
															
																|  | 
 |