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:
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;