clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit ed7de4967af46afb3c3ef8802a3d4686d267d415
parent 3635053539feb212e20ddd7a4b9e17fd26ff3114
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Wed, 14 Jul 2021 10:19:50 +0200

More work on the remote GUI


Diffstat:
Mexamples/plugins/CMakeLists.txt | 1+
Mexamples/plugins/buffer.hh | 54++++++++++++++++++++++++++++++++++++++++++++----------
Mexamples/plugins/remote-channel.cc | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mexamples/plugins/remote-channel.hh | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mexamples/plugins/remote-gui.cc | 2+-
Mexamples/plugins/remote-gui.hh | 7++++++-
6 files changed, 188 insertions(+), 19 deletions(-)

diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt @@ -15,6 +15,7 @@ add_library( remote-gui.cc remote-channel.hh remote-channel.cc + buffer.hh dc-offset/dc-offset.hh dc-offset/dc-offset.cc diff --git a/examples/plugins/buffer.hh b/examples/plugins/buffer.hh @@ -1,34 +1,68 @@ #pragma once +#include <algorithm> #include <array> +#include <cassert> #include <cstddef> -#include <cstdint> -#include <cstring> namespace clap { - template <size_t CAPACITY> + template <typename T, size_t CAPACITY> class Buffer { + public: + Buffer() { assert(checkInvariants()); } - const uint8_t *readData() const noexcept { return &data_[roff_]; } + Buffer(const Buffer<T, CAPACITY> &) = delete; + Buffer(Buffer<T, CAPACITY> &&) = delete; + Buffer<T, CAPACITY> &operator=(const Buffer<T, CAPACITY> &) = delete; + Buffer<T, CAPACITY> &operator=(Buffer<T, CAPACITY> &&) = delete; + + const T *readData() const noexcept { return &data_[roff_]; } size_t readAvail() const noexcept { return woff_ - roff_; } - void read(size_t bytes) noexcept { roff_ += bytes; } + void read(size_t bytes) noexcept { + roff_ += bytes; + assert(checkInvariants()); + } - uint8_t *writeData() const noexcept { return &data_[woff_]; } + void write(const T *&data, size_t &size) { + auto avail = std::min(size, writeAvail()); + auto end = data + avail; + std::copy(data, data + avail, writeData()); + data = end; + size -= avail; + } + T *writeData() noexcept { return &data_[woff_]; } size_t writeAvail() const noexcept { return CAPACITY - woff_; } - void wrote(size_t bytes) noexcept { woff_ += bytes; } + void wrote(size_t bytes) noexcept { + woff_ += bytes; + assert(checkInvariants()); + } - void rewind() { + void rewind() noexcept { if (woff_ == 0) return; // this is inefficient but simple // TODO: use scatter/gather IO - std::memmove(&data_[0], &data_[roff_], woff_ - roff_); + auto rptr = readData(); + auto avail = readAvail(); + std::copy(rptr, rptr + avail, &data_[0]); + woff_ -= roff_; roff_ = 0; + + assert(checkInvariants()); + } + + private: +#ifndef NDEBUG + bool checkInvariants() const noexcept { + assert(woff_ <= data_.size()); + assert(roff_ <= woff_); + return true; } +#endif - std::array<uint8_t, CAPACITY> data_; + std::array<T, CAPACITY> data_; size_t roff_ = 0; size_t woff_ = 0; }; diff --git a/examples/plugins/remote-channel.cc b/examples/plugins/remote-channel.cc @@ -1,4 +1,5 @@ #ifdef __unix__ +# include <errno.h> # include <unistd.h> #endif @@ -6,10 +7,77 @@ namespace clap { - RemoteChannel::RemoteChannel(int socket) : socket_(socket) {} + RemoteChannel::RemoteChannel(Handler &handler, EventControl &evControl, int socket) + : handler_(handler), evControl_(evControl), socket_(socket) {} RemoteChannel::~RemoteChannel() { close(); } + void RemoteChannel::onRead() { + ssize_t nbytes = ::read(socket_, inputBuffer_.writeData(), inputBuffer_.writeAvail()); + if (nbytes < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) + return; + + close(); + return; + } + + inputBuffer_.wrote(nbytes); + parseInput(); + inputBuffer_.rewind(); + } + + void RemoteChannel::write(const uint8_t *data, size_t size) { + while (size > 0) { + auto &buffer = nextWriteBuffer(); + buffer.write(data, size); + } + + assert(size == 0); + } + + RemoteChannel::WriteBuffer &RemoteChannel::nextWriteBuffer() { + if (outputBuffers_.empty()) { + outputBuffers_.emplace(); + return outputBuffers_.back(); + } + + auto &buffer = outputBuffers_.back(); + if (buffer.writeAvail() > 0) + return buffer; + + outputBuffers_.emplace(); + return outputBuffers_.back(); + } + + void RemoteChannel::onWrite() { + while (!outputBuffers_.empty()) { + auto &buffer = outputBuffers_.front(); + + auto avail = buffer.readAvail(); + while (avail > 0) { + auto nbytes = ::write(socket_, buffer.readData(), avail); + if (nbytes == -1) { + if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) { + evControl_.modifyFd(CLAP_FD_READ | CLAP_FD_WRITE); + return; + } + + close(); + return; + } + + buffer.wrote(nbytes); + avail -= nbytes; + assert(avail == buffer.readAvail()); + } + + outputBuffers_.pop(); + } + + evControl_.modifyFd(CLAP_FD_READ); + } + void RemoteChannel::close() { if (socket_ == -1) return; diff --git a/examples/plugins/remote-channel.hh b/examples/plugins/remote-channel.hh @@ -1,19 +1,80 @@ #pragma once +#include <queue> +#include <memory> + +#include <clap/all.h> + +#include "buffer.hh" + namespace clap { class RemoteChannel final { public: - RemoteChannel(int socket); + class EventControl { + public: + virtual void modifyFd(clap_fd_flags flags); + }; + + class Handler { + public: + virtual ~Handler() = default; + + // GUI callbacks + virtual void defineParameter(const clap_param_info &info) {} + virtual bool attachCocoa(void *nsView) { return false; } + virtual bool attachWin32(clap_hwnd window) { return false; } + virtual bool attachX11(const char *display_name, unsigned long window) { return false; } + + virtual void size(int32_t *width, int32_t *height) {} + virtual void setScale(double scale) {} + + virtual bool show() { return false; } + virtual bool hide() { return false; } + + virtual void close() {} + + // Plugin callbacks + virtual void beginAdjust(clap_id paramId) {} + virtual void adjust(clap_id paramId, double value) {} + virtual void endAdjust(clap_id paramId) {} + }; + + RemoteChannel(Handler &handler, EventControl &evControl, clap_fd socket); ~RemoteChannel(); - RemoteChannel(const RemoteChannel&) = delete; - RemoteChannel(RemoteChannel&&) = delete; - RemoteChannel& operator=(const RemoteChannel&) = delete; - RemoteChannel& operator=(RemoteChannel&&) = delete; + RemoteChannel(const RemoteChannel &) = delete; + RemoteChannel(RemoteChannel &&) = delete; + RemoteChannel &operator=(const RemoteChannel &) = delete; + RemoteChannel &operator=(RemoteChannel &&) = delete; + + void defineParameter(const clap_param_info &info); + void setParameterValue(clap_id paramId, double value); void close(); + // Called when there is data to be read, non-blocking + void onRead(); + + // Called when data can be written, non-blocking + void onWrite(); + + + + private: - int socket_; + using ReadBuffer = Buffer<uint8_t, 128 * 1024>; + using WriteBuffer = Buffer<uint8_t, 32 * 1024>; + + void write(const uint8_t *data, size_t size); + WriteBuffer& nextWriteBuffer(); + + void parseInput(); + + Handler &handler_; + EventControl &evControl_; + clap_fd socket_; + + ReadBuffer inputBuffer_; + std::queue<WriteBuffer> outputBuffers_; }; } // namespace clap \ No newline at end of file diff --git a/examples/plugins/remote-gui.cc b/examples/plugins/remote-gui.cc @@ -40,7 +40,7 @@ namespace clap { ::close(sockets[1]); } - channel_.reset(new RemoteChannel(sockets[0])); + channel_.reset(new RemoteChannel(*this, *this, sockets[0])); return true; #else diff --git a/examples/plugins/remote-gui.hh b/examples/plugins/remote-gui.hh @@ -10,7 +10,7 @@ #include "remote-channel.hh" namespace clap { - class RemoteGui : public AbstractGui { + class RemoteGui : public AbstractGui, public RemoteChannel::Handler, public RemoteChannel::EventControl { RemoteGui(PluginHelper &plugin) : AbstractGui(plugin) {} bool spawn(); @@ -27,6 +27,11 @@ namespace clap { void close() noexcept override; + // RemoteChannel::Handler + void beginAdjust(clap_id paramId) override; + void adjust(clap_id paramId, double value) override; + void endAdjust(clap_id paramId) override; + private: std::unique_ptr<RemoteChannel> channel_;