diff --git a/system_modules/napaudio/src/audio/component/levelmetercomponent.cpp b/system_modules/napaudio/src/audio/component/levelmetercomponent.cpp index 2fdd1dfc85..4e68b80ca9 100755 --- a/system_modules/napaudio/src/audio/component/levelmetercomponent.cpp +++ b/system_modules/napaudio/src/audio/component/levelmetercomponent.cpp @@ -49,6 +49,7 @@ namespace nap mMeter = nodeManager.makeSafe(nodeManager, mResource->mAnalysisWindowSize); mMeter->setType(mResource->mMeterType); + nodeManager.registerRootProcess(mMeter.get()); if (mResource->mFilterInput) { diff --git a/system_modules/napaudio/src/audio/component/outputcomponent.cpp b/system_modules/napaudio/src/audio/component/outputcomponent.cpp index 9bfe46b97e..f6f5848e41 100644 --- a/system_modules/napaudio/src/audio/component/outputcomponent.cpp +++ b/system_modules/napaudio/src/audio/component/outputcomponent.cpp @@ -60,6 +60,7 @@ namespace nap // If the channel is out of bounds we create a PullNode instead of an OutputNode in order to process the connected DSP branch. auto pullNode = nodeManager.makeSafe(nodeManager); pullNode->audioInput.connect(*mInput->getOutputForChannel(mChannelRouting[channel])); + nodeManager.registerRootProcess(pullNode.get()); mOutputs.emplace_back(std::move(pullNode)); continue; } @@ -67,6 +68,7 @@ namespace nap auto outputNode = nodeManager.makeSafe(nodeManager); outputNode->setOutputChannel(channel); outputNode->audioInput.connect(*mInput->getOutputForChannel(mChannelRouting[channel])); + nodeManager.registerRootProcess(outputNode.get()); mOutputs.emplace_back(std::move(outputNode)); } } diff --git a/system_modules/napaudio/src/audio/core/audionodemanager.cpp b/system_modules/napaudio/src/audio/core/audionodemanager.cpp index 83111e4408..6e1f45045a 100644 --- a/system_modules/napaudio/src/audio/core/audionodemanager.cpp +++ b/system_modules/napaudio/src/audio/core/audionodemanager.cpp @@ -57,7 +57,8 @@ namespace nap { for (auto& root : mRootProcesses) - root->process(); + if (root != nullptr) + root->update(); } for (auto channel = 0; channel < mOutputChannelCount; ++channel) { @@ -101,7 +102,8 @@ namespace nap { for (auto& root : mRootProcesses) - root->update(); + if (root != nullptr) + root->update(); } for (auto channel = 0; channel < mOutputChannelCount; ++channel) { @@ -162,40 +164,59 @@ namespace nap } - void NodeManager::registerProcess(Process& process) + void NodeManager::registerProcess(SafePtr process) { - process.setSampleRate(mSampleRate); - process.setBufferSize(mInternalBufferSize); + process->setSampleRate(mSampleRate); + process->setBufferSize(mInternalBufferSize); auto oldSampleRate = mSampleRate; auto oldBufferSize = mInternalBufferSize; - enqueueTask([&, oldSampleRate, oldBufferSize]() { + + enqueueTask([&, oldSampleRate, oldBufferSize, process]() { + // Check if the Process is not (being) deleted + if (process == nullptr) + return; + // In the extremely rare case the buffersize or the samplerate of the node manager have been changed in between the enqueueing of the task and its execution on the audio thread, we set them again. // However we prefer not to, in order to avoid memory allocation on the audio thread. if (oldSampleRate != mSampleRate) - process.setSampleRate(mSampleRate); + process->setSampleRate(mSampleRate); if (oldBufferSize != mInternalBufferSize) - process.setBufferSize(mInternalBufferSize); - process.mRegisteredWithNodeManager.store(true); - mProcesses.emplace(&process); + process->setBufferSize(mInternalBufferSize); + process->mRegisteredWithNodeManager.store(true); + mProcesses.emplace_back(process.get()); }); } void NodeManager::unregisterProcess(Process& process) { - mProcesses.erase(&process); + auto it = std::find_if(mProcesses.begin(), mProcesses.end(), [&](auto& el){ return el == &process; }); + if (it != mProcesses.end()) + mProcesses.erase(it); } - void NodeManager::registerRootProcess(Process& rootProcess) + void NodeManager::registerRootProcess(SafePtr rootProcess) { - enqueueTask([&]() { mRootProcesses.emplace(&rootProcess); }); + enqueueTask([&, rootProcess]() + { + if (rootProcess == nullptr) + return; + mRootProcesses.emplace_back(rootProcess); + }); } - void NodeManager::unregisterRootProcess(Process& rootProcess) + void NodeManager::unregisterRootProcess(SafePtr rootProcess) { - mRootProcesses.erase(&rootProcess); + enqueueTask([&, rootProcess]() + { + if (rootProcess == nullptr) + return; + auto it = std::find_if(mRootProcesses.begin(), mRootProcesses.end(), [&](auto &el){ return el.get() == rootProcess.get(); }); + if (it != mRootProcesses.end()) + mRootProcesses.erase(it); + }); } diff --git a/system_modules/napaudio/src/audio/core/audionodemanager.h b/system_modules/napaudio/src/audio/core/audionodemanager.h index 474463315e..cbce7b32b3 100644 --- a/system_modules/napaudio/src/audio/core/audionodemanager.h +++ b/system_modules/napaudio/src/audio/core/audionodemanager.h @@ -136,19 +136,20 @@ namespace nap void setInternalBufferSize(int size); /** - * Used by nodes to register themselves to be processed directly by the node manager + * Use this to register a Process as root process. Called from control thread. * @param rootProcess The root process is a process or node that is executed on every audio callback without being connected to an input of another node. * In most cases the root process is an OutputNode. */ - void registerRootProcess(Process& rootProcess); + void registerRootProcess(SafePtr rootProcess); /** - * Used by nodes to unregister themselves to be processed directly by the node manager. + * Use this to manually unregister a Process as root process. Called from control thread. + * Note: Processes also unregister themselves as root process automatically from their destructors. * @param rootProcess The root process is a process or node that is executed on every audio callback without being connected to an input of another node. * In most cases the root process is an OutputNode. */ - void unregisterRootProcess(Process& rootProcess); + void unregisterRootProcess(SafePtr rootProcess); /** * Constructs an object managed by a SafeOwner that will dispose the object in the NodeManager's DeletionQueue when it is no longer used. @@ -161,6 +162,15 @@ namespace nap SafeOwner makeSafe(Args&& ... args) { auto owner = SafeOwner(mDeletionQueue, new T(std::forward(args)...)); + + // If the newly constructed object is a Process, set its internal SafePtr to itself, and register it. + Process* process = rtti_cast(owner.getRaw()); + if (process != nullptr) + { + process->mSelf = owner.get(); + registerProcess(owner.get()); + } + return owner; } @@ -175,6 +185,15 @@ namespace nap SafeOwner makeSafe(T* ptr) { auto owner = SafeOwner(mDeletionQueue, ptr); + + // If the newly constructed object is a Process, set its internal SafePtr to itself, and register it. + Process* process = rtti_cast(owner.getRaw()); + if (process != nullptr) + { + process->mSelf = owner.get(); + registerProcess(owner.get()); + } + return owner; } @@ -191,7 +210,7 @@ namespace nap private: // Used by the nodes and audio processes to register themselves on construction - void registerProcess(Process& process); + void registerProcess(SafePtr process); // Used by the nodes and audio processes to unregister themselves on destruction void unregisterProcess(Process& process); @@ -230,8 +249,8 @@ namespace nap std::vector mInputBuffer; // Pointing to the audio input that this node manager has to process. The format is a non-interleaved array containing a float array for each channel. - std::set mProcesses; // all the audio processes managed by this node manager - std::set mRootProcesses; // the nodes that will be processed directly by the manager on every audio callback + std::vector mProcesses; // all the audio processes managed by this node manager + std::vector> mRootProcesses; // the nodes that will be processed directly by the manager on every audio callback nap::TaskQueue mTaskQueue = { 256 }; // Queue with lambda functions to be executed before processing the next internal buffer. DeletionQueue& mDeletionQueue; // Deletion queue used to safely create and destruct nodes in a threadsafe manner. diff --git a/system_modules/napaudio/src/audio/core/audiopin.cpp b/system_modules/napaudio/src/audio/core/audiopin.cpp index 022c68e992..18a6856e97 100644 --- a/system_modules/napaudio/src/audio/core/audiopin.cpp +++ b/system_modules/napaudio/src/audio/core/audiopin.cpp @@ -4,13 +4,15 @@ #include "audiopin.h" -// Std includes -#include - // Audio includes #include