Worker thread per plugin instance.
This commit is contained in:
@@ -46,7 +46,6 @@ namespace pipedal {
|
||||
virtual int GetNumberOfInputAudioChannels() const = 0;
|
||||
virtual int GetNumberOfOutputAudioChannels() 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;
|
||||
|
||||
|
||||
+8
-4
@@ -41,6 +41,7 @@
|
||||
#include "AudioHost.hpp"
|
||||
#include <exception>
|
||||
#include "RingBufferReader.hpp"
|
||||
#include "Worker.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
namespace fs = std::filesystem;
|
||||
@@ -70,6 +71,11 @@ Lv2Effect::Lv2Effect(
|
||||
|
||||
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.
|
||||
if (info->piPedalUI())
|
||||
{
|
||||
@@ -179,10 +185,8 @@ Lv2Effect::Lv2Effect(
|
||||
const LV2_Worker_Interface *worker_interface =
|
||||
(const LV2_Worker_Interface *)lilv_instance_get_extension_data(pInstance,
|
||||
LV2_WORKER__interface);
|
||||
if (worker_interface)
|
||||
{
|
||||
this->worker = std::make_unique<Worker>(pHost->GetHostWorkerThread(), pInstance, worker_interface);
|
||||
}
|
||||
this->worker = std::make_unique<Worker>(workerThread, pInstance, worker_interface);
|
||||
|
||||
const LV2_State_Interface *state_interface =
|
||||
(const LV2_State_Interface *)lilv_instance_get_extension_data(pInstance,
|
||||
LV2_STATE__interface);
|
||||
|
||||
+5
-2
@@ -40,12 +40,12 @@
|
||||
#include "StateInterface.hpp"
|
||||
#include "LogFeature.hpp"
|
||||
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
|
||||
class RealtimeRingBufferWriter;
|
||||
class IPatchWriterCallback;
|
||||
class HostWorkerThread;
|
||||
|
||||
class Lv2Effect : public IEffect, private LogFeature::LogMessageListener
|
||||
{
|
||||
@@ -57,6 +57,10 @@ namespace pipedal
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::shared_ptr<HostWorkerThread> workerThread;
|
||||
std::unique_ptr<Worker> worker;
|
||||
|
||||
std::unordered_map<std::string,int> controlIndex;
|
||||
|
||||
FileBrowserFilesFeature fileBrowserFilesFeature;
|
||||
@@ -70,7 +74,6 @@ namespace pipedal
|
||||
int numberOfOutputs = 0;
|
||||
int numberOfMidiInputs = 0;
|
||||
|
||||
std::unique_ptr<Worker> worker;
|
||||
LilvInstance *pInstance;
|
||||
std::shared_ptr<Lv2PluginInfo> info;
|
||||
std::vector<float> controlValues;
|
||||
|
||||
+8
-5
@@ -47,6 +47,7 @@
|
||||
#include "StdErrorCapture.hpp"
|
||||
#include "util.hpp"
|
||||
#include "ModFileTypes.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#include "Locale.hpp"
|
||||
|
||||
@@ -301,7 +302,6 @@ PluginHost::PluginHost()
|
||||
|
||||
this->urids = new Urids(mapFeature);
|
||||
|
||||
pHostWorkerThread = std::make_shared<HostWorkerThread>();
|
||||
}
|
||||
|
||||
void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings)
|
||||
@@ -1668,10 +1668,6 @@ bool Lv2PluginInfo::isSplit() const
|
||||
{
|
||||
return uri_ == SPLIT_PEDALBOARD_ITEM_URI;
|
||||
}
|
||||
std::shared_ptr<HostWorkerThread> PluginHost::GetHostWorkerThread()
|
||||
{
|
||||
return pHostWorkerThread;
|
||||
}
|
||||
|
||||
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)
|
||||
// {
|
||||
// Lv2Log::error("%s",error.c_str());
|
||||
|
||||
+2
-2
@@ -454,6 +454,8 @@ namespace pipedal
|
||||
LV2_PROPERTY_GETSET(patchProperties)
|
||||
LV2_PROPERTY_GETSET(hasDefaultState)
|
||||
|
||||
bool WantsWorkerThread() const;
|
||||
|
||||
const Lv2PortInfo &getPort(const std::string &symbol)
|
||||
{
|
||||
for (size_t i = 0; i < ports_.size(); ++i)
|
||||
@@ -913,7 +915,6 @@ namespace pipedal
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<HostWorkerThread> pHostWorkerThread;
|
||||
// IHost implementation.
|
||||
virtual void SetMaxAudioBufferSize(size_t size) { maxBufferSize = size; }
|
||||
virtual size_t GetMaxAudioBufferSize() const { return maxBufferSize; }
|
||||
@@ -922,7 +923,6 @@ namespace pipedal
|
||||
virtual int GetNumberOfInputAudioChannels() const { return numberOfAudioInputChannels; }
|
||||
virtual int GetNumberOfOutputAudioChannels() const { return numberOfAudioOutputChannels; }
|
||||
virtual LV2_Feature *const *GetLv2Features() const { return (LV2_Feature *const *)&(this->lv2Features[0]); }
|
||||
virtual std::shared_ptr<HostWorkerThread> GetHostWorkerThread();
|
||||
|
||||
public:
|
||||
virtual MapFeature &GetMapFeature() override { return this->mapFeature; }
|
||||
|
||||
+24
-8
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
// (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
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -242,8 +242,19 @@ void HostWorkerThread::ThreadProc() noexcept
|
||||
HostWorkerThread::HostWorkerThread()
|
||||
{
|
||||
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()
|
||||
@@ -252,10 +263,12 @@ void HostWorkerThread::Close()
|
||||
bool sendClose = false;
|
||||
{
|
||||
std::lock_guard lock{submitMutex};
|
||||
if (!closed)
|
||||
{
|
||||
closed = true;
|
||||
sendClose = true;
|
||||
if (pThread) {
|
||||
if (!closed)
|
||||
{
|
||||
closed = true;
|
||||
sendClose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sendClose)
|
||||
@@ -278,7 +291,10 @@ LV2_Worker_Status HostWorkerThread::ScheduleWork(Worker *worker, size_t size, co
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
+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
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/worker/worker.h"
|
||||
#include "condition_variable"
|
||||
#include <atomic>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -51,10 +52,12 @@ namespace pipedal {
|
||||
HostWorkerThread();
|
||||
~HostWorkerThread();
|
||||
|
||||
bool StartThread();
|
||||
void Close();
|
||||
bool Closed() const { return closed || pThread == nullptr; }
|
||||
LV2_Worker_Status ScheduleWork(Worker*worker, size_t size, const void*data);
|
||||
private:
|
||||
bool closed = false;
|
||||
std::atomic<bool> closed = false;
|
||||
std::unique_ptr<std::thread> pThread;
|
||||
void ThreadProc() noexcept;
|
||||
|
||||
@@ -64,8 +67,6 @@ namespace pipedal {
|
||||
|
||||
std::vector<uint8_t> dataBuffer;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
class Worker {
|
||||
@@ -75,8 +76,8 @@ namespace pipedal {
|
||||
LilvInstance*lilvInstance;
|
||||
const LV2_Worker_Interface*workerInterface;
|
||||
|
||||
bool closed = false;
|
||||
bool exiting = false;
|
||||
std::atomic<bool> closed = false;
|
||||
std::atomic<bool> exiting = false;
|
||||
RingBuffer<true,false> responseRingBuffer;
|
||||
|
||||
std::vector<uint8_t> responseBuffer;
|
||||
@@ -94,6 +95,7 @@ namespace pipedal {
|
||||
public:
|
||||
Worker(const std::shared_ptr<HostWorkerThread>& pHostWorker,LilvInstance *instance, const LV2_Worker_Interface *iface);
|
||||
~Worker();
|
||||
|
||||
void Close();
|
||||
|
||||
LV2_Worker_Status ScheduleWork(
|
||||
|
||||
Reference in New Issue
Block a user