Implement Lv2 Worker (#6484)
This commit is contained in:
committed by
Johannes Lorenz
parent
83777dc1f7
commit
33d1baddc0
@@ -197,6 +197,7 @@ public:
|
||||
|
||||
// audio-device-stuff
|
||||
|
||||
bool renderOnly() const { return m_renderOnly; }
|
||||
// Returns the current audio device's name. This is not necessarily
|
||||
// the user's preferred audio device, in case you were thinking that.
|
||||
inline const QString & audioDevName() const
|
||||
|
||||
93
include/LmmsSemaphore.h
Normal file
93
include/LmmsSemaphore.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Semaphore.h - Semaphore declaration
|
||||
*
|
||||
* Copyright (c) 2022-2022 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* 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 (at your option) 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code has been copied and adapted from https://github.com/drobilla/jalv
|
||||
* File src/zix/sem.h
|
||||
*/
|
||||
|
||||
#ifndef LMMS_SEMAPHORE_H
|
||||
#define LMMS_SEMAPHORE_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_BUILD_APPLE
|
||||
# include <mach/mach.h>
|
||||
#elif defined(LMMS_BUILD_WIN32)
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace lmms {
|
||||
|
||||
/**
|
||||
A counting semaphore.
|
||||
|
||||
This is an integer that is always positive, and has two main operations:
|
||||
increment (post) and decrement (wait). If a decrement can not be performed
|
||||
(i.e. the value is 0) the caller will be blocked until another thread posts
|
||||
and the operation can succeed.
|
||||
|
||||
Semaphores can be created with any starting value, but typically this will
|
||||
be 0 so the semaphore can be used as a simple signal where each post
|
||||
corresponds to one wait.
|
||||
|
||||
Semaphores are very efficient (much moreso than a mutex/cond pair). In
|
||||
particular, at least on Linux, post is async-signal-safe, which means it
|
||||
does not block and will not be interrupted. If you need to signal from
|
||||
a realtime thread, this is the most appropriate primitive to use.
|
||||
|
||||
@note Likely outdated with C++20's std::counting_semaphore
|
||||
(though we have to check that this will be RT conforming on all platforms)
|
||||
*/
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(unsigned initial);
|
||||
Semaphore(const Semaphore&) = delete;
|
||||
Semaphore& operator=(const Semaphore&) = delete;
|
||||
Semaphore(Semaphore&&) = delete;
|
||||
Semaphore& operator=(Semaphore&&) = delete;
|
||||
~Semaphore();
|
||||
|
||||
void post();
|
||||
void wait();
|
||||
bool tryWait();
|
||||
|
||||
private:
|
||||
#ifdef LMMS_BUILD_APPLE
|
||||
semaphore_t m_sem;
|
||||
#elif defined(LMMS_BUILD_WIN32)
|
||||
HANDLE m_sem;
|
||||
#else
|
||||
sem_t m_sem;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_SEMAPHORE_H
|
||||
@@ -51,13 +51,14 @@ public:
|
||||
std::size_t capacity() const {return m_buffer.maximum_eventual_write_space();}
|
||||
std::size_t free() const {return m_buffer.write_space();}
|
||||
void wakeAll() {m_notifier.wakeAll();}
|
||||
std::size_t write(const sampleFrame *src, std::size_t cnt, bool notify = false)
|
||||
std::size_t write(const T *src, std::size_t cnt, bool notify = false)
|
||||
{
|
||||
std::size_t written = LocklessRingBuffer<T>::m_buffer.write(src, cnt);
|
||||
// Let all waiting readers know new data are available.
|
||||
if (notify) {LocklessRingBuffer<T>::m_notifier.wakeAll();}
|
||||
return written;
|
||||
}
|
||||
void mlock() { m_buffer.mlock(); }
|
||||
|
||||
protected:
|
||||
ringbuffer_t<T> m_buffer;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Lv2Proc.h - Lv2 processor class
|
||||
*
|
||||
* Copyright (c) 2019-2020 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
* Copyright (c) 2019-2022 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
@@ -31,11 +31,14 @@
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "LinkedModelGroups.h"
|
||||
#include "LmmsSemaphore.h"
|
||||
#include "Lv2Basics.h"
|
||||
#include "Lv2Features.h"
|
||||
#include "Lv2Options.h"
|
||||
#include "LinkedModelGroups.h"
|
||||
#include "Lv2Worker.h"
|
||||
#include "Plugin.h"
|
||||
#include "../src/3rdparty/ringbuffer/include/ringbuffer/ringbuffer.h"
|
||||
#include "TimePos.h"
|
||||
@@ -174,8 +177,14 @@ private:
|
||||
const LilvPlugin* m_plugin;
|
||||
LilvInstance* m_instance;
|
||||
Lv2Features m_features;
|
||||
|
||||
// options
|
||||
Lv2Options m_options;
|
||||
|
||||
// worker
|
||||
std::optional<Lv2Worker> m_worker;
|
||||
Semaphore m_workLock; // this must be shared by different workers
|
||||
|
||||
// full list of ports
|
||||
std::vector<std::unique_ptr<Lv2Ports::PortBase>> m_ports;
|
||||
// quick reference to specific, unique ports
|
||||
|
||||
93
include/Lv2Worker.h
Normal file
93
include/Lv2Worker.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Lv2Worker.h - Lv2Worker class
|
||||
*
|
||||
* Copyright (c) 2022-2022 Johannes Lorenz <jlsf2013$users.sourceforge.net, $=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* 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 (at your option) 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV2WORKER_H
|
||||
#define LV2WORKER_H
|
||||
|
||||
#include "lmmsconfig.h"
|
||||
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|
||||
#include <lilv/lilv.h>
|
||||
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "LocklessRingBuffer.h"
|
||||
#include "LmmsSemaphore.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
/**
|
||||
Worker container
|
||||
*/
|
||||
class Lv2Worker
|
||||
{
|
||||
public:
|
||||
// CTOR/DTOR/feature access
|
||||
Lv2Worker(const LV2_Worker_Interface* iface, Semaphore* common_work_lock, bool threaded);
|
||||
~Lv2Worker();
|
||||
void setHandle(LV2_Handle handle) { m_handle = handle; }
|
||||
LV2_Worker_Schedule* feature() { return &m_scheduleFeature; }
|
||||
|
||||
// public API
|
||||
void emitResponses();
|
||||
void notifyPluginThatRunFinished()
|
||||
{
|
||||
if(m_iface->end_run) { m_iface->end_run(m_scheduleFeature.handle); }
|
||||
}
|
||||
|
||||
// to be called only by static functions
|
||||
LV2_Worker_Status scheduleWork(uint32_t size, const void* data);
|
||||
LV2_Worker_Status respond(uint32_t size, const void* data);
|
||||
|
||||
private:
|
||||
// functions
|
||||
void workerFunc();
|
||||
std::size_t bufferSize() const; //!< size of internal buffers
|
||||
|
||||
// parameters
|
||||
const LV2_Worker_Interface* m_iface;
|
||||
bool m_threaded;
|
||||
LV2_Handle m_handle;
|
||||
LV2_Worker_Schedule m_scheduleFeature;
|
||||
|
||||
// threading/synchronization
|
||||
std::thread m_thread;
|
||||
std::vector<char> m_response; //!< buffer where single requests from m_requests are unpacked
|
||||
LocklessRingBuffer<char> m_requests, m_responses; //!< ringbuffer to queue multiple requests
|
||||
LocklessRingBufferReader<char> m_requestsReader, m_responsesReader;
|
||||
std::atomic<bool> m_exit = false; //!< Whether the worker function should keep looping
|
||||
Semaphore m_sem;
|
||||
Semaphore* m_workLock;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_HAVE_LV2
|
||||
|
||||
#endif // LV2WORKER_H
|
||||
|
||||
Reference in New Issue
Block a user