clap

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

commit e18f3c2ac6beae12cd026fcfbcafdeacbaa2da25
parent dcc8840e030f2b862f2ac2b4f31239314ba02492
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Sat, 28 Aug 2021 22:42:49 +0200

Initial work on custom knobs and re-usable qml components

Diffstat:
Mexamples/gui/application.cc | 4++++
Mexamples/gui/parameter-proxy.cc | 4++++
Mexamples/gui/parameter-proxy.hh | 6++----
Mexamples/plugins/dc-offset/skin/main.qml | 13++++---------
Mexamples/plugins/path-provider.cc | 4++++
Mexamples/plugins/path-provider.hh | 1+
Aexamples/plugins/qml/clap/Knob.qml | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/plugins/qml/clap/qmldir | 4++++
Mexamples/plugins/remote-gui.cc | 3+++
9 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/examples/gui/application.cc b/examples/gui/application.cc @@ -19,9 +19,11 @@ Application::Application(int &argc, char **argv) QCommandLineOption skinOpt("skin", tr("path to the skin directory"), tr("path")); QCommandLineOption socketOpt("socket", tr("path to the QML skin"), tr("path")); + QCommandLineOption qmlLibOpt("qml-import", tr("QML import path"), tr("path")); parser.addOption(skinOpt); parser.addOption(socketOpt); + parser.addOption(qmlLibOpt); parser.addHelpOption(); parser.process(*this); @@ -29,6 +31,8 @@ Application::Application(int &argc, char **argv) pluginProxy_ = new PluginProxy(this); auto qmlContext = quickView_->engine()->rootContext(); + for (const auto &str : parser.values(qmlLibOpt)) + quickView_->engine()->addImportPath(str); qmlContext->setContextProperty("plugin", pluginProxy_); quickView_->setSource(parser.value(skinOpt) + "/main.qml"); diff --git a/examples/gui/parameter-proxy.cc b/examples/gui/parameter-proxy.cc @@ -39,6 +39,10 @@ void ParameterProxy::setIsAdjusting(bool isAdjusting) { } void ParameterProxy::setValueFromUI(double value) { + value = std::max(minValue_, std::min(maxValue_, value)); + if (value == value_) + return; + value_ = value; clap::messages::AdjustRequest rq{id_, value_, 0}; diff --git a/examples/gui/parameter-proxy.hh b/examples/gui/parameter-proxy.hh @@ -53,14 +53,12 @@ public: double normalize(double value) const { double delta = maxValue_ - minValue_; - return delta != 0 ? (value - minValue_) / delta : 0; + return delta != 0 ? std::min(1., std::max(0., (value - minValue_) / delta)) : 0; } double denormalize(double value) const { - Q_ASSERT(value >= 0); - Q_ASSERT(value <= 1); double delta = maxValue_ - minValue_; - return minValue_ + value * delta; + return minValue_ + std::min(1., std::max(0., value)) * delta; } signals: diff --git a/examples/plugins/dc-offset/skin/main.qml b/examples/plugins/dc-offset/skin/main.qml @@ -1,20 +1,15 @@ import QtQuick 2.1 import QtQuick.Controls 2.1 +import clap 1.0 Rectangle { width: 300 height: 200 color: "#224477" - Dial { + Knob { id: dc_offset_knob - property QtObject param: plugin.param(0) - from: param.minValue - to: param.maxValue - value: param.value - inputMode: Dial.Vertical - onMoved: { - param.value = value; - } + param: plugin.param(0) + size: 80 } } \ No newline at end of file diff --git a/examples/plugins/path-provider.cc b/examples/plugins/path-provider.cc @@ -24,6 +24,8 @@ namespace clap { std::string getSkinDirectory() const override { return prefix_ / "lib/clap/" / pluginName_ / "skin"; } + std::string getQmlLibDirectory() const override { return prefix_ / "lib/clap" / pluginName_ / "qml"; } + bool isValid() const noexcept override { return !prefix_.empty(); } private: @@ -59,6 +61,8 @@ namespace clap { std::string getSkinDirectory() const override { return srcRoot_ / "examples/plugins/" / pluginName_ / "skin"; } + std::string getQmlLibDirectory() const override { return srcRoot_ / "examples/plugins/qml"; } + bool isValid() const noexcept override { return !srcRoot_.empty() && !buildRoot_.empty(); } private: diff --git a/examples/plugins/path-provider.hh b/examples/plugins/path-provider.hh @@ -12,6 +12,7 @@ namespace clap { virtual std::string getGuiExecutable() const = 0; virtual std::string getSkinDirectory() const = 0; + virtual std::string getQmlLibDirectory() const = 0; virtual bool isValid() const = 0; }; diff --git a/examples/plugins/qml/clap/Knob.qml b/examples/plugins/qml/clap/Knob.qml @@ -0,0 +1,72 @@ +import QtQuick 2.1 +import QtQuick.Controls 2.1 + +Item { + property QtObject param + property int size: 20 + id: knob + width: size + height: size + + Rectangle { + width: knob.size + height: knob.size + radius: knob.size / 2 + color: "#332277" + + MouseArea { + anchors.fill: parent + drag.axis: Drag.YAxis + property real lastY: 0 + onPressed: (mouse) => { + if (mouse.button === Qt.LeftButton) { + lastY = mouse.y; + knob.param.isAdjusting = true + } + } + onReleased: (mouse) => { + if (mouse.button === Qt.LeftButton) { + knob.param.isAdjusting = false + } + } + onPositionChanged: (mouse) => { + if (!(mouse.buttons & Qt.LeftButton)) + return; + knob.param.normalizedValue += ((mouse.modifiers & Qt.ShiftModifier) ? 0.001 : 0.01) * (mouse.y - lastY); + lastY = mouse.y; + } + } + } + + Item { + Rectangle { + x: knob.size / 2 - knob.size / 40 + y: knob.size / 20 + height: knob.size / 10 + width: knob.size / 20 + radius: knob.size / 40 + color: "#2282ff" + } + + transform: Rotation { + angle: knob.param.normalizedModulation * 270 - 135 + origin.x: knob.size / 2 + origin.y: knob.size / 2 + } + } + + Rectangle { + x: knob.size / 2 - knob.size / 20 + y: knob.size / 20 + height: knob.size / 10 + width: knob.size / 10 + radius: knob.size / 40 + color: "#dd82ff" + } + + transform: Rotation { + angle: knob.param.normalizedValue * 270 - 135 + origin.x: knob.size / 2 + origin.y: knob.size / 2 + } +} diff --git a/examples/plugins/qml/clap/qmldir b/examples/plugins/qml/clap/qmldir @@ -0,0 +1,3 @@ +module clap + +Knob 1.0 Knob.qml +\ No newline at end of file diff --git a/examples/plugins/remote-gui.cc b/examples/plugins/remote-gui.cc @@ -49,12 +49,15 @@ namespace clap { ::snprintf(socketStr, sizeof(socketStr), "%d", sockets[1]); auto path = pathProvider.getGuiExecutable(); auto skin = pathProvider.getSkinDirectory(); + auto qmlLib = pathProvider.getQmlLibDirectory(); ::execl(path.c_str(), path.c_str(), "--socket", socketStr, "--skin", skin.c_str(), + "--qml-import", + qmlLib.c_str(), (const char *)nullptr); printf("Failed to start child process: %m\n"); std::terminate();