clap

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

commit 0e83938ef834d0a0d88438dba4a8c1132a02db80
parent 4c51dd70ec0e2ad9d9b4b51ad74e981505d406bb
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Wed, 15 Sep 2021 12:16:50 +0200

gui: add a transport proxy

Diffstat:
Mexamples/plugins/gui/CMakeLists.txt | 2++
Mexamples/plugins/gui/application.cc | 10++++++++++
Mexamples/plugins/gui/application.hh | 2++
Mexamples/plugins/gui/plugin-proxy.cc | 3+--
Aexamples/plugins/gui/transport-proxy.cc | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/plugins/gui/transport-proxy.hh | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/plugins/io/messages.hh | 7+++++++
7 files changed, 235 insertions(+), 2 deletions(-)

diff --git a/examples/plugins/gui/CMakeLists.txt b/examples/plugins/gui/CMakeLists.txt @@ -13,6 +13,8 @@ add_executable(clap-gui parameter-proxy.cc plugin-proxy.hh plugin-proxy.cc + transport-proxy.hh + transport-proxy.cc ) target_link_libraries(clap-gui clap-io Qt6::Quick) diff --git a/examples/plugins/gui/application.cc b/examples/plugins/gui/application.cc @@ -16,6 +16,7 @@ Application::Application(int &argc, char **argv) ; qmlRegisterType<ParameterProxy>("org.clap", 1, 0, "ParameterProxy"); + qmlRegisterType<TransportProxy>("org.clap", 1, 0, "TransportProxy"); qmlRegisterType<PluginProxy>("org.clap", 1, 0, "PluginProxy"); QCommandLineParser parser; @@ -32,11 +33,13 @@ Application::Application(int &argc, char **argv) parser.process(*this); _pluginProxy = new PluginProxy(this); + _transportProxy = new TransportProxy(this); auto qmlContext = _quickView->engine()->rootContext(); for (const auto &str : parser.values(qmlLibOpt)) _quickView->engine()->addImportPath(str); qmlContext->setContextProperty("plugin", _pluginProxy); + qmlContext->setContextProperty("transport", _transportProxy); _quickView->setSource(parser.value(skinOpt) + "/main.qml"); @@ -100,6 +103,13 @@ void Application::onMessage(const clap::RemoteChannel::Message &msg) { quit(); break; + case clap::messages::kUpdateTransportRequest: { + clap::messages::UpdateTransportRequest rq; + msg.get(rq); + _transportProxy->update(rq.hasTransport, rq.transport); + break; + } + case clap::messages::kDefineParameterRequest: { clap::messages::DefineParameterRequest rq; msg.get(rq); diff --git a/examples/plugins/gui/application.hh b/examples/plugins/gui/application.hh @@ -6,6 +6,7 @@ #include "../io/remote-channel.hh" #include "plugin-proxy.hh" +#include "transport-proxy.hh" class QQuickView; @@ -33,4 +34,5 @@ private: std::unique_ptr<clap::RemoteChannel> _remoteChannel; PluginProxy *_pluginProxy = nullptr; + TransportProxy *_transportProxy = nullptr; }; \ No newline at end of file diff --git a/examples/plugins/gui/plugin-proxy.cc b/examples/plugins/gui/plugin-proxy.cc @@ -14,8 +14,7 @@ ParameterProxy *PluginProxy::param(clap_id paramId) { QString PluginProxy::toString() const { return "Plugin"; } -void PluginProxy::defineParameter(const clap_param_info &info) -{ +void PluginProxy::defineParameter(const clap_param_info &info) { auto it = _parameters.emplace(info.id, new ParameterProxy(info, this)); if (!it.second) it.first->second->redefine(info); diff --git a/examples/plugins/gui/transport-proxy.cc b/examples/plugins/gui/transport-proxy.cc @@ -0,0 +1,61 @@ +#include "transport-proxy.hh" + +TransportProxy::TransportProxy(QObject *parent) : QObject(parent) {} + +void TransportProxy::update(bool hasTransport, const clap_event_transport &transport) { + update(_hasTransport, hasTransport, &TransportProxy::hasTransportChanged); + + update<bool>(_hasBeatsTimeline, + transport.flags & CLAP_TRANSPORT_HAS_BEATS_TIMELINE, + &TransportProxy::hasBeatsTimelineChanged); + update<bool>(_hasSecondsTimeline, + transport.flags & CLAP_TRANSPORT_HAS_SECONDS_TIMELINE, + &TransportProxy::hasSecondsTimelineChanged); + update<bool>(_hasTimeSignature, + transport.flags & CLAP_TRANSPORT_HAS_TIME_SIGNATURE, + &TransportProxy::hasTimeSignatureChanged); + update<bool>( + _isPlaying, transport.flags & CLAP_TRANSPORT_IS_PLAYING, &TransportProxy::isPlayingChanged); + update<bool>(_isRecording, + transport.flags & CLAP_TRANSPORT_IS_RECORDING, + &TransportProxy::isRecordingChanged); + update<bool>(_isLoopActive, + transport.flags & CLAP_TRANSPORT_IS_LOOP_ACTIVE, + &TransportProxy::isLoopActiveChanged); + update<bool>(_isWithinPreRoll, + transport.flags & CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL, + &TransportProxy::isWithinPreRollChanged); + + update(_songPositionBeats, + transport.song_pos_beats / double(CLAP_BEATTIME_FACTOR), + &TransportProxy::songPositionBeatsChanged); + update(_songPositionSeconds, + transport.song_pos_seconds / double(CLAP_SECTIME_FACTOR), + &TransportProxy::songPositionSecondsChanged); + + update(_tempo, transport.tempo, &TransportProxy::tempoChanged); + + update(_barStart, + transport.bar_start / double(CLAP_BEATTIME_FACTOR), + &TransportProxy::barStartChanged); + update(_barNumber, transport.bar_number, &TransportProxy::barNumberChanged); + + update(_loopStartBeats, + transport.loop_start_beats / double(CLAP_BEATTIME_FACTOR), + &TransportProxy::loopStartBeatsChanged); + update(_loopEndBeats, + transport.loop_end_beats / double(CLAP_BEATTIME_FACTOR), + &TransportProxy::loopEndBeatsChanged); + update(_loopStartSeconds, + transport.loop_start_seconds / double(CLAP_SECTIME_FACTOR), + &TransportProxy::loopStartSecondsChanged); + update(_loopEndSeconds, + transport.loop_end_seconds / double(CLAP_SECTIME_FACTOR), + &TransportProxy::loopEndSecondsChanged); + + update<int>( + _timeSignatureNumerator, transport.tsig_num, &TransportProxy::timeSignatureNumeratorChanged); + update<int>(_timeSignatureDenominator, + transport.tsig_denom, + &TransportProxy::timeSignatureDenominatorChanged); +} +\ No newline at end of file diff --git a/examples/plugins/gui/transport-proxy.hh b/examples/plugins/gui/transport-proxy.hh @@ -0,0 +1,150 @@ +#pragma once + +#include <QObject> + +#include <clap/all.h> + +class TransportProxy : public QObject { + Q_OBJECT + Q_PROPERTY(bool hasTransport READ hasTransport NOTIFY hasTransportChanged) + + Q_PROPERTY(bool hasBeatsTimeline READ hasBeatsTimeline NOTIFY hasBeatsTimelineChanged) + Q_PROPERTY(bool hasSecondsTimeline READ hasSecondsTimeline NOTIFY hasSecondsTimelineChanged) + Q_PROPERTY(bool hasTimeSignature READ hasTimeSignature NOTIFY hasTimeSignatureChanged) + Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY isPlayingChanged) + Q_PROPERTY(bool isRecording READ isRecording NOTIFY isRecordingChanged) + Q_PROPERTY(bool isLoopActive READ isLoopActive NOTIFY isLoopActiveChanged) + Q_PROPERTY(bool isWithinPreRoll READ isWithinPreRoll NOTIFY isWithinPreRollChanged) + + Q_PROPERTY(double songPositionBeats READ getSongPositionBeats NOTIFY songPositionBeatsChanged) + Q_PROPERTY( + double songPositionSeconds READ getSongPositionSeconds NOTIFY songPositionSecondsChanged) + + Q_PROPERTY(double tempo READ getTempo NOTIFY tempoChanged) + + Q_PROPERTY(double barStart READ getBarStart NOTIFY barStartChanged) + Q_PROPERTY(int barNumber READ getBarNumber NOTIFY barNumberChanged) + + Q_PROPERTY(double loopStartBeats READ getLoopStartBeats NOTIFY loopStartBeatsChanged) + Q_PROPERTY(double loopEndBeats READ getLoopEndBeats NOTIFY loopEndBeatsChanged) + Q_PROPERTY(double loopStartSeconds READ getLoopStartSeconds NOTIFY loopStartSecondsChanged) + Q_PROPERTY(double loopEndSeconds READ getLoopEndSeconds NOTIFY loopEndSecondsChanged) + + Q_PROPERTY(int timeSignatureNumerator READ getTimeSignatureNumerator NOTIFY + timeSignatureNumeratorChanged) + Q_PROPERTY(int timeSignatureDenominator READ getTimeSignatureDenominator NOTIFY + timeSignatureDenominatorChanged) + +public: + explicit TransportProxy(QObject *parent = nullptr); + + void update(bool hasTransport, const clap_event_transport &transport); + + [[nodiscard]] bool hasTransport() const noexcept { return _hasTransport; } + + [[nodiscard]] bool hasBeatsTimeline() const noexcept { return _hasBeatsTimeline; } + + [[nodiscard]] bool hasSecondsTimeline() const noexcept { return _hasSecondsTimeline; } + + [[nodiscard]] bool hasTimeSignature() const noexcept { return _hasTimeSignature; } + + [[nodiscard]] bool isPlaying() const noexcept { return _isPlaying; } + + [[nodiscard]] bool isRecording() const noexcept { return _isRecording; } + + [[nodiscard]] bool isLoopActive() const noexcept { return _isLoopActive; } + + [[nodiscard]] bool isWithinPreRoll() const noexcept { return _isWithinPreRoll; } + + [[nodiscard]] double getSongPositionBeats() const noexcept { return _songPositionBeats; } + + [[nodiscard]] double getSongPositionSeconds() const noexcept { return _songPositionSeconds; } + + [[nodiscard]] double getTempo() const noexcept { return _tempo; } + + [[nodiscard]] double getBarStart() const noexcept { return _barStart; } + + [[nodiscard]] int getBarNumber() const noexcept { return _barNumber; } + + [[nodiscard]] double getLoopStartBeats() const noexcept { return _loopStartBeats; } + + [[nodiscard]] double getLoopEndBeats() const noexcept { return _loopEndBeats; } + + [[nodiscard]] double getLoopStartSeconds() const noexcept { return _loopStartSeconds; } + + [[nodiscard]] double getLoopEndSeconds() const noexcept { return _loopEndSeconds; } + + [[nodiscard]] int getTimeSignatureNumerator() const noexcept { return _timeSignatureNumerator; } + + [[nodiscard]] int getTimeSignatureDenominator() const noexcept { + return _timeSignatureDenominator; + } + +signals: + void updated(); + + void hasTransportChanged(); + + void hasBeatsTimelineChanged(); + void hasSecondsTimelineChanged(); + void hasTimeSignatureChanged(); + void isPlayingChanged(); + void isRecordingChanged(); + void isLoopActiveChanged(); + void isWithinPreRollChanged(); + + void songPositionBeatsChanged(); + void songPositionSecondsChanged(); + + void tempoChanged(); + + void barStartChanged(); + void barNumberChanged(); + + void loopStartBeatsChanged(); + void loopEndBeatsChanged(); + void loopStartSecondsChanged(); + void loopEndSecondsChanged(); + + void timeSignatureNumeratorChanged(); + void timeSignatureDenominatorChanged(); + +private: + + using NotifyType = void (TransportProxy::*)(); + + template <typename T> + void update(T& attr, T value, NotifyType notify) + { + if (value == attr) + return; + attr = value; + (this->*notify)(); + } + + bool _hasTransport = false; + + bool _hasBeatsTimeline = false; + bool _hasSecondsTimeline = false; + bool _hasTimeSignature = false; + bool _isPlaying = false; + bool _isRecording = false; + bool _isLoopActive = false; + bool _isWithinPreRoll = false; + + double _songPositionBeats = 0; + double _songPositionSeconds = 0; + + double _tempo = 0; + + double _barStart = 0; + int _barNumber = 0; + + double _loopStartBeats = 0; + double _loopEndBeats = 0; + double _loopStartSeconds = 0; + double _loopEndSeconds = 0; + + int _timeSignatureNumerator = 0; + int _timeSignatureDenominator = 0; +}; +\ No newline at end of file diff --git a/examples/plugins/io/messages.hh b/examples/plugins/io/messages.hh @@ -8,6 +8,7 @@ namespace clap::messages { // DSP->GUI kDefineParameterRequest, kParameterValueRequest, + kUpdateTransportRequest, // GUI->DSP kAdjustRequest, @@ -49,6 +50,12 @@ namespace clap::messages { clap_param_info info; }; + struct UpdateTransportRequest final { + static const constexpr Type type = kUpdateTransportRequest; + bool hasTransport; + clap_event_transport transport; + }; + struct ParameterValueRequest final { static const constexpr Type type = kParameterValueRequest; clap_id paramId;