Worker thread per plugin instance.
This commit is contained in:
Vendored
+1
-1
@@ -163,7 +163,7 @@
|
|||||||
"cSpell.ignoreWords": [
|
"cSpell.ignoreWords": [
|
||||||
"nammodel"
|
"nammodel"
|
||||||
],
|
],
|
||||||
"cSpell.enabled": true,
|
"cSpell.enabled": false,
|
||||||
|
|
||||||
// Disable all automatic completion suggestions - only show when Ctrl+Space is pressed
|
// Disable all automatic completion suggestions - only show when Ctrl+Space is pressed
|
||||||
"editor.quickSuggestions": {
|
"editor.quickSuggestions": {
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ namespace pipedal {
|
|||||||
virtual int GetNumberOfInputAudioChannels() const = 0;
|
virtual int GetNumberOfInputAudioChannels() const = 0;
|
||||||
virtual int GetNumberOfOutputAudioChannels() const = 0;
|
virtual int GetNumberOfOutputAudioChannels() const = 0;
|
||||||
virtual std::shared_ptr<Lv2PluginInfo> GetPluginInfo(const std::string &uri) const = 0;
|
virtual std::shared_ptr<Lv2PluginInfo> GetPluginInfo(const std::string &uri) const = 0;
|
||||||
virtual std::shared_ptr<HostWorkerThread> GetHostWorkerThread() = 0;
|
|
||||||
|
|
||||||
virtual IEffect *CreateEffect(PedalboardItem &pedalboard) = 0;
|
virtual IEffect *CreateEffect(PedalboardItem &pedalboard) = 0;
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -41,6 +41,7 @@
|
|||||||
#include "AudioHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include "RingBufferReader.hpp"
|
#include "RingBufferReader.hpp"
|
||||||
|
#include "Worker.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@@ -70,6 +71,11 @@ Lv2Effect::Lv2Effect(
|
|||||||
|
|
||||||
this->bypass = pedalboardItem.isEnabled();
|
this->bypass = pedalboardItem.isEnabled();
|
||||||
|
|
||||||
|
this->workerThread = std::make_unique<HostWorkerThread>();
|
||||||
|
if (info_->WantsWorkerThread())
|
||||||
|
{
|
||||||
|
workerThread->StartThread();
|
||||||
|
}
|
||||||
// stash a list of known file properties that we want to keep synced.
|
// stash a list of known file properties that we want to keep synced.
|
||||||
if (info->piPedalUI())
|
if (info->piPedalUI())
|
||||||
{
|
{
|
||||||
@@ -179,10 +185,8 @@ Lv2Effect::Lv2Effect(
|
|||||||
const LV2_Worker_Interface *worker_interface =
|
const LV2_Worker_Interface *worker_interface =
|
||||||
(const LV2_Worker_Interface *)lilv_instance_get_extension_data(pInstance,
|
(const LV2_Worker_Interface *)lilv_instance_get_extension_data(pInstance,
|
||||||
LV2_WORKER__interface);
|
LV2_WORKER__interface);
|
||||||
if (worker_interface)
|
this->worker = std::make_unique<Worker>(workerThread, pInstance, worker_interface);
|
||||||
{
|
|
||||||
this->worker = std::make_unique<Worker>(pHost->GetHostWorkerThread(), pInstance, worker_interface);
|
|
||||||
}
|
|
||||||
const LV2_State_Interface *state_interface =
|
const LV2_State_Interface *state_interface =
|
||||||
(const LV2_State_Interface *)lilv_instance_get_extension_data(pInstance,
|
(const LV2_State_Interface *)lilv_instance_get_extension_data(pInstance,
|
||||||
LV2_STATE__interface);
|
LV2_STATE__interface);
|
||||||
|
|||||||
+5
-2
@@ -40,12 +40,12 @@
|
|||||||
#include "StateInterface.hpp"
|
#include "StateInterface.hpp"
|
||||||
#include "LogFeature.hpp"
|
#include "LogFeature.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
|
|
||||||
class RealtimeRingBufferWriter;
|
class RealtimeRingBufferWriter;
|
||||||
class IPatchWriterCallback;
|
class IPatchWriterCallback;
|
||||||
|
class HostWorkerThread;
|
||||||
|
|
||||||
class Lv2Effect : public IEffect, private LogFeature::LogMessageListener
|
class Lv2Effect : public IEffect, private LogFeature::LogMessageListener
|
||||||
{
|
{
|
||||||
@@ -57,6 +57,10 @@ namespace pipedal
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<HostWorkerThread> workerThread;
|
||||||
|
std::unique_ptr<Worker> worker;
|
||||||
|
|
||||||
std::unordered_map<std::string,int> controlIndex;
|
std::unordered_map<std::string,int> controlIndex;
|
||||||
|
|
||||||
FileBrowserFilesFeature fileBrowserFilesFeature;
|
FileBrowserFilesFeature fileBrowserFilesFeature;
|
||||||
@@ -70,7 +74,6 @@ namespace pipedal
|
|||||||
int numberOfOutputs = 0;
|
int numberOfOutputs = 0;
|
||||||
int numberOfMidiInputs = 0;
|
int numberOfMidiInputs = 0;
|
||||||
|
|
||||||
std::unique_ptr<Worker> worker;
|
|
||||||
LilvInstance *pInstance;
|
LilvInstance *pInstance;
|
||||||
std::shared_ptr<Lv2PluginInfo> info;
|
std::shared_ptr<Lv2PluginInfo> info;
|
||||||
std::vector<float> controlValues;
|
std::vector<float> controlValues;
|
||||||
|
|||||||
+8
-5
@@ -47,6 +47,7 @@
|
|||||||
#include "StdErrorCapture.hpp"
|
#include "StdErrorCapture.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "ModFileTypes.hpp"
|
#include "ModFileTypes.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Locale.hpp"
|
#include "Locale.hpp"
|
||||||
|
|
||||||
@@ -301,7 +302,6 @@ PluginHost::PluginHost()
|
|||||||
|
|
||||||
this->urids = new Urids(mapFeature);
|
this->urids = new Urids(mapFeature);
|
||||||
|
|
||||||
pHostWorkerThread = std::make_shared<HostWorkerThread>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings)
|
void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings)
|
||||||
@@ -1668,10 +1668,6 @@ bool Lv2PluginInfo::isSplit() const
|
|||||||
{
|
{
|
||||||
return uri_ == SPLIT_PEDALBOARD_ITEM_URI;
|
return uri_ == SPLIT_PEDALBOARD_ITEM_URI;
|
||||||
}
|
}
|
||||||
std::shared_ptr<HostWorkerThread> PluginHost::GetHostWorkerThread()
|
|
||||||
{
|
|
||||||
return pHostWorkerThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResourceInfo
|
class ResourceInfo
|
||||||
{
|
{
|
||||||
@@ -1883,6 +1879,13 @@ Lv2PatchPropertyInfo::Lv2PatchPropertyInfo(PluginHost *pluginHost, const LilvNod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ffs.
|
||||||
|
static inline bool contains(const std::vector<std::string> &vec, const std::string &value) {
|
||||||
|
return std::find(vec.begin(),vec.end(),value) != vec.end();
|
||||||
|
}
|
||||||
|
bool Lv2PluginInfo::WantsWorkerThread() const {
|
||||||
|
return contains(this->required_features_,LV2_WORKER__schedule) || contains(this->supported_features_,LV2_WORKER__schedule);
|
||||||
|
}
|
||||||
// void PiPedalHostLogError(const std::string &error)
|
// void PiPedalHostLogError(const std::string &error)
|
||||||
// {
|
// {
|
||||||
// Lv2Log::error("%s",error.c_str());
|
// Lv2Log::error("%s",error.c_str());
|
||||||
|
|||||||
+2
-2
@@ -454,6 +454,8 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET(patchProperties)
|
LV2_PROPERTY_GETSET(patchProperties)
|
||||||
LV2_PROPERTY_GETSET(hasDefaultState)
|
LV2_PROPERTY_GETSET(hasDefaultState)
|
||||||
|
|
||||||
|
bool WantsWorkerThread() const;
|
||||||
|
|
||||||
const Lv2PortInfo &getPort(const std::string &symbol)
|
const Lv2PortInfo &getPort(const std::string &symbol)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < ports_.size(); ++i)
|
for (size_t i = 0; i < ports_.size(); ++i)
|
||||||
@@ -913,7 +915,6 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<HostWorkerThread> pHostWorkerThread;
|
|
||||||
// IHost implementation.
|
// IHost implementation.
|
||||||
virtual void SetMaxAudioBufferSize(size_t size) { maxBufferSize = size; }
|
virtual void SetMaxAudioBufferSize(size_t size) { maxBufferSize = size; }
|
||||||
virtual size_t GetMaxAudioBufferSize() const { return maxBufferSize; }
|
virtual size_t GetMaxAudioBufferSize() const { return maxBufferSize; }
|
||||||
@@ -922,7 +923,6 @@ namespace pipedal
|
|||||||
virtual int GetNumberOfInputAudioChannels() const { return numberOfAudioInputChannels; }
|
virtual int GetNumberOfInputAudioChannels() const { return numberOfAudioInputChannels; }
|
||||||
virtual int GetNumberOfOutputAudioChannels() const { return numberOfAudioOutputChannels; }
|
virtual int GetNumberOfOutputAudioChannels() const { return numberOfAudioOutputChannels; }
|
||||||
virtual LV2_Feature *const *GetLv2Features() const { return (LV2_Feature *const *)&(this->lv2Features[0]); }
|
virtual LV2_Feature *const *GetLv2Features() const { return (LV2_Feature *const *)&(this->lv2Features[0]); }
|
||||||
virtual std::shared_ptr<HostWorkerThread> GetHostWorkerThread();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual MapFeature &GetMapFeature() override { return this->mapFeature; }
|
virtual MapFeature &GetMapFeature() override { return this->mapFeature; }
|
||||||
|
|||||||
+24
-8
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
// (Borrows heavily from worker.c by David Robillard.)
|
// (Borrows heavily from worker.c by David Robillard.)
|
||||||
|
|
||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2024 Robin Davies
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
// this software and associated documentation files (the "Software"), to deal in
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
@@ -242,8 +242,19 @@ void HostWorkerThread::ThreadProc() noexcept
|
|||||||
HostWorkerThread::HostWorkerThread()
|
HostWorkerThread::HostWorkerThread()
|
||||||
{
|
{
|
||||||
this->dataBuffer.resize(16*1024);
|
this->dataBuffer.resize(16*1024);
|
||||||
pThread = std::make_unique<std::thread>([this]()
|
}
|
||||||
{ this->ThreadProc(); });
|
|
||||||
|
bool HostWorkerThread::StartThread()
|
||||||
|
{
|
||||||
|
if (!pThread)
|
||||||
|
{
|
||||||
|
if (closed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pThread = std::make_unique<std::thread>([this]()
|
||||||
|
{ this->ThreadProc(); });
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostWorkerThread::Close()
|
void HostWorkerThread::Close()
|
||||||
@@ -252,10 +263,12 @@ void HostWorkerThread::Close()
|
|||||||
bool sendClose = false;
|
bool sendClose = false;
|
||||||
{
|
{
|
||||||
std::lock_guard lock{submitMutex};
|
std::lock_guard lock{submitMutex};
|
||||||
if (!closed)
|
if (pThread) {
|
||||||
{
|
if (!closed)
|
||||||
closed = true;
|
{
|
||||||
sendClose = true;
|
closed = true;
|
||||||
|
sendClose = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sendClose)
|
if (sendClose)
|
||||||
@@ -278,7 +291,10 @@ LV2_Worker_Status HostWorkerThread::ScheduleWork(Worker *worker, size_t size, co
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(submitMutex);
|
std::lock_guard lock(submitMutex);
|
||||||
|
|
||||||
if (exiting)
|
if (!StartThread()) { // ensures thread is running, when plugins haven't declared they want a worker thread.
|
||||||
|
return LV2_Worker_Status::LV2_WORKER_ERR_NO_SPACE;
|
||||||
|
}
|
||||||
|
if (exiting )
|
||||||
{
|
{
|
||||||
return LV2_Worker_Status::LV2_WORKER_ERR_NO_SPACE;
|
return LV2_Worker_Status::LV2_WORKER_ERR_NO_SPACE;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2025 Robin Davies
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
// this software and associated documentation files (the "Software"), to deal in
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "lv2/atom/atom.h"
|
#include "lv2/atom/atom.h"
|
||||||
#include "lv2/worker/worker.h"
|
#include "lv2/worker/worker.h"
|
||||||
#include "condition_variable"
|
#include "condition_variable"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -51,10 +52,12 @@ namespace pipedal {
|
|||||||
HostWorkerThread();
|
HostWorkerThread();
|
||||||
~HostWorkerThread();
|
~HostWorkerThread();
|
||||||
|
|
||||||
|
bool StartThread();
|
||||||
void Close();
|
void Close();
|
||||||
|
bool Closed() const { return closed || pThread == nullptr; }
|
||||||
LV2_Worker_Status ScheduleWork(Worker*worker, size_t size, const void*data);
|
LV2_Worker_Status ScheduleWork(Worker*worker, size_t size, const void*data);
|
||||||
private:
|
private:
|
||||||
bool closed = false;
|
std::atomic<bool> closed = false;
|
||||||
std::unique_ptr<std::thread> pThread;
|
std::unique_ptr<std::thread> pThread;
|
||||||
void ThreadProc() noexcept;
|
void ThreadProc() noexcept;
|
||||||
|
|
||||||
@@ -64,8 +67,6 @@ namespace pipedal {
|
|||||||
|
|
||||||
std::vector<uint8_t> dataBuffer;
|
std::vector<uint8_t> dataBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Worker {
|
class Worker {
|
||||||
@@ -75,8 +76,8 @@ namespace pipedal {
|
|||||||
LilvInstance*lilvInstance;
|
LilvInstance*lilvInstance;
|
||||||
const LV2_Worker_Interface*workerInterface;
|
const LV2_Worker_Interface*workerInterface;
|
||||||
|
|
||||||
bool closed = false;
|
std::atomic<bool> closed = false;
|
||||||
bool exiting = false;
|
std::atomic<bool> exiting = false;
|
||||||
RingBuffer<true,false> responseRingBuffer;
|
RingBuffer<true,false> responseRingBuffer;
|
||||||
|
|
||||||
std::vector<uint8_t> responseBuffer;
|
std::vector<uint8_t> responseBuffer;
|
||||||
@@ -94,6 +95,7 @@ namespace pipedal {
|
|||||||
public:
|
public:
|
||||||
Worker(const std::shared_ptr<HostWorkerThread>& pHostWorker,LilvInstance *instance, const LV2_Worker_Interface *iface);
|
Worker(const std::shared_ptr<HostWorkerThread>& pHostWorker,LilvInstance *instance, const LV2_Worker_Interface *iface);
|
||||||
~Worker();
|
~Worker();
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
LV2_Worker_Status ScheduleWork(
|
LV2_Worker_Status ScheduleWork(
|
||||||
|
|||||||
Reference in New Issue
Block a user