diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-03-21 17:33:41 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-04-13 23:55:27 +0200 |
commit | 051fb2f94f6364b80219a3c671bb953d2e54a140 (patch) | |
tree | d76351f995884acbada1e26b5fe869daf5f4a8a1 | |
parent | 94e7374bad0da0d9d132401bd57526b509497c7d (diff) |
proto/osc: add open sound control output method
-rw-r--r-- | proto-osc/CMakeLists.txt | 15 | ||||
-rw-r--r-- | proto-osc/dialog.cpp | 38 | ||||
-rw-r--r-- | proto-osc/dialog.hpp | 29 | ||||
-rw-r--r-- | proto-osc/dialog.ui | 131 | ||||
-rw-r--r-- | proto-osc/images/osc-icon.png | bin | 0 -> 868 bytes | |||
-rw-r--r-- | proto-osc/lang/nl_NL.ts | 45 | ||||
-rw-r--r-- | proto-osc/lang/ru_RU.ts | 45 | ||||
-rw-r--r-- | proto-osc/lang/stub.ts | 45 | ||||
-rw-r--r-- | proto-osc/lang/zh_CN.ts | 45 | ||||
-rw-r--r-- | proto-osc/metadata.cpp | 8 | ||||
-rw-r--r-- | proto-osc/metadata.hpp | 10 | ||||
-rw-r--r-- | proto-osc/osc-res.qrc | 5 | ||||
-rw-r--r-- | proto-osc/proto.cpp | 54 | ||||
-rw-r--r-- | proto-osc/proto.hpp | 29 | ||||
-rw-r--r-- | proto-osc/settings.hpp | 14 |
15 files changed, 513 insertions, 0 deletions
diff --git a/proto-osc/CMakeLists.txt b/proto-osc/CMakeLists.txt new file mode 100644 index 00000000..eeaf206c --- /dev/null +++ b/proto-osc/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SDK_OSCPACK "" CACHE PATH "oscpack build directory") +if(SDK_OSCPACK) + if(WIN32) + if(NOT EXISTS "${SDK_OSCPACK}/include/.") + message(FATAL_ERROR "SDK_OSCPACK should have 'include' subdirectory (or symlink) to src dir") + endif() + link_directories("${SDK_OSCPACK}") + include_directories("${SDK_OSCPACK}/include" "${SDK_OSCPACK}/include/oscpack") + else() + link_directories("${SDK_OSCPACK}/lib" "${SDK_OSCPACK}/lib32") + include_directories("${SDK_OSCPACK}/include/oscpack") + endif() + link_libraries(oscpack) + otr_module(proto-osc) +endif() diff --git a/proto-osc/dialog.cpp b/proto-osc/dialog.cpp new file mode 100644 index 00000000..54bf6885 --- /dev/null +++ b/proto-osc/dialog.cpp @@ -0,0 +1,38 @@ +#include "dialog.hpp" +#include <QHostAddress> +#include <QPalette> + +void osc_dialog::host_address_edited(const QString& str) +{ + bool bad = QHostAddress{str}.isNull(); + auto pal = pal_; + for (auto role : { QPalette::Highlight, QPalette::Window }) + if (bad) + pal.setColor(role, Qt::red); + ui.address->setPalette(pal); +} + +osc_dialog::osc_dialog() : + pal_{palette()} +{ + ui.setupUi( this ); + + tie_setting(s.address, ui.address); + tie_setting(s.port, ui.port); + connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &osc_dialog::doOK); + connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &osc_dialog::doCancel); + connect(ui.address, &QLineEdit::textChanged, this, &osc_dialog::host_address_edited); + host_address_edited(ui.address->text()); +} + +void osc_dialog::save() { s.b->save(); } +void osc_dialog::reload() { s.b->reload(); } + +void osc_dialog::doOK() { s.b->save(); close(); } +void osc_dialog::doCancel() { close(); } + +void osc_dialog::register_protocol(IProtocol*) {} +void osc_dialog::unregister_protocol() {} + +bool osc_dialog::embeddable() noexcept { return true; } +void osc_dialog::set_buttons_visible(bool x) noexcept { ui.buttonBox->setVisible(x); } diff --git a/proto-osc/dialog.hpp b/proto-osc/dialog.hpp new file mode 100644 index 00000000..29682843 --- /dev/null +++ b/proto-osc/dialog.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "settings.hpp" +#include "ui_dialog.h" +#include "api/plugin-api.hpp" + +class osc_dialog: public IProtocolDialog +{ + Q_OBJECT + +public: + osc_dialog(); + void register_protocol(IProtocol*) override; + void unregister_protocol() override; +private: + void set_buttons_visible(bool x) noexcept override; + bool embeddable() noexcept override; + void save() override; + void reload() override; + + Ui_OSC_Dialog ui; + osc_settings s; + const QPalette pal_; + +private slots: + void doOK(); + void doCancel(); + void host_address_edited(const QString& str); +}; diff --git a/proto-osc/dialog.ui b/proto-osc/dialog.ui new file mode 100644 index 00000000..5a078bbd --- /dev/null +++ b/proto-osc/dialog.ui @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>OSC_Dialog</class> + <widget class="QWidget" name="OSC_Dialog"> + <property name="windowModality"> + <enum>Qt::NonModal</enum> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>284</width> + <height>102</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>284</width> + <height>102</height> + </size> + </property> + <property name="windowTitle"> + <string>OSC protocol settings</string> + </property> + <property name="windowIcon"> + <iconset resource="osc-res.qrc"> + <normaloff>:/images/osc-icon.png</normaloff>:/images/osc-icon.png</iconset> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Destination address</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="address"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="maxLength"> + <number>256</number> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Port</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="port"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>65535</number> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../gui/opentrack-res.qrc"/> + <include location="osc-res.qrc"/> + </resources> + <connections/> + <designerdata> + <property name="gridDeltaX"> + <number>5</number> + </property> + <property name="gridDeltaY"> + <number>5</number> + </property> + <property name="gridSnapX"> + <bool>true</bool> + </property> + <property name="gridSnapY"> + <bool>true</bool> + </property> + <property name="gridVisible"> + <bool>false</bool> + </property> + </designerdata> + <slots> + <slot>startEngineClicked()</slot> + <slot>stopEngineClicked()</slot> + <slot>cameraSettingsClicked()</slot> + </slots> +</ui> diff --git a/proto-osc/images/osc-icon.png b/proto-osc/images/osc-icon.png Binary files differnew file mode 100644 index 00000000..3ef546e9 --- /dev/null +++ b/proto-osc/images/osc-icon.png diff --git a/proto-osc/lang/nl_NL.ts b/proto-osc/lang/nl_NL.ts new file mode 100644 index 00000000..260b7adc --- /dev/null +++ b/proto-osc/lang/nl_NL.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="nl_NL"> +<context> + <name>OSC_Dialog</name> + <message> + <source>OSC protocol settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Port</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Destination address</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_metadata</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_proto</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error binding socket to INADDR_ANY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid destination address '%1'</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/proto-osc/lang/ru_RU.ts b/proto-osc/lang/ru_RU.ts new file mode 100644 index 00000000..498d68d6 --- /dev/null +++ b/proto-osc/lang/ru_RU.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="ru_RU"> +<context> + <name>OSC_Dialog</name> + <message> + <source>OSC protocol settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Port</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Destination address</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_metadata</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_proto</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error binding socket to INADDR_ANY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid destination address '%1'</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/proto-osc/lang/stub.ts b/proto-osc/lang/stub.ts new file mode 100644 index 00000000..20828cbd --- /dev/null +++ b/proto-osc/lang/stub.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +<context> + <name>OSC_Dialog</name> + <message> + <source>OSC protocol settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Port</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Destination address</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_metadata</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_proto</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error binding socket to INADDR_ANY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid destination address '%1'</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/proto-osc/lang/zh_CN.ts b/proto-osc/lang/zh_CN.ts new file mode 100644 index 00000000..e0d49844 --- /dev/null +++ b/proto-osc/lang/zh_CN.ts @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="zh_CN"> +<context> + <name>OSC_Dialog</name> + <message> + <source>OSC protocol settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Port</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Destination address</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_metadata</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>osc_proto</name> + <message> + <source>Open Sound Control</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Error binding socket to INADDR_ANY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>%1: %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid destination address '%1'</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/proto-osc/metadata.cpp b/proto-osc/metadata.cpp new file mode 100644 index 00000000..9d69347d --- /dev/null +++ b/proto-osc/metadata.cpp @@ -0,0 +1,8 @@ +#include "metadata.hpp" +#include "proto.hpp" +#include "dialog.hpp" + +QString osc_metadata::name() { return tr("Open Sound Control"); } +QIcon osc_metadata::icon() { return QIcon(":/images/osc-icon.png"); } + +OPENTRACK_DECLARE_PROTOCOL(osc_proto, osc_dialog, osc_metadata) diff --git a/proto-osc/metadata.hpp b/proto-osc/metadata.hpp new file mode 100644 index 00000000..c0a947aa --- /dev/null +++ b/proto-osc/metadata.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "api/plugin-api.hpp" + +class osc_metadata : public Metadata +{ + Q_OBJECT + + QString name() override; + QIcon icon() override; +}; diff --git a/proto-osc/osc-res.qrc b/proto-osc/osc-res.qrc new file mode 100644 index 00000000..ade4c629 --- /dev/null +++ b/proto-osc/osc-res.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>images/osc-icon.png</file> + </qresource> +</RCC> diff --git a/proto-osc/proto.cpp b/proto-osc/proto.cpp new file mode 100644 index 00000000..2f90957c --- /dev/null +++ b/proto-osc/proto.cpp @@ -0,0 +1,54 @@ +#include "proto.hpp" +#include "ui_dialog.h" +#include "api/plugin-api.hpp" +#include <QQuaternion> +#include <QHostAddress> +#include "osc/OscOutboundPacketStream.h" + +osc_proto::osc_proto() +{ + auto reload_fn = [this] { + dest = QHostAddress{s.address }; + port = (unsigned short)s.port; + }; + connect(&*s.b, &bundle_::changed, this, reload_fn); + connect(&*s.b, &bundle_::reloading, this, reload_fn); +} + +void osc_proto::pose(const double* data, const double*) +{ + if (dest.isNull()) + return; + + static constexpr unsigned buffer_size = 1024; + char buffer[buffer_size] = {}; + osc::OutboundPacketStream p{buffer, buffer_size}; + auto q = QQuaternion::fromEulerAngles((float)data[Pitch], (float)data[Yaw], (float)-data[Roll]).normalized(); + p << osc::BeginMessage("/bridge/quat") << q.scalar() << q.x() << q.y() << q.z() << osc::EndMessage; + sock.writeDatagram(p.Data(), (int)p.Size(), dest, port); +} + +module_status osc_proto::initialize() +{ + QString error; + + dest = QHostAddress{s.address }; + port = (unsigned short)s.port; + + if (dest.isNull()) + { + error = tr("Invalid destination address '%1'").arg(s.address); + goto fail; + } + + if (!sock.bind()) + { + error = tr("Error binding socket to INADDR_ANY"); + goto fail; + } + + return status_ok(); + +fail: + return { tr("%1: %2").arg(error, sock.errorString()) }; +} diff --git a/proto-osc/proto.hpp b/proto-osc/proto.hpp new file mode 100644 index 00000000..53a5dee4 --- /dev/null +++ b/proto-osc/proto.hpp @@ -0,0 +1,29 @@ +#pragma once + +/* Copyright (c) 2023 Stanislaw Halik <sthalik@misaki.pl> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "settings.hpp" +#include "api/plugin-api.hpp" +#include <QUdpSocket> +#include <QHostAddress> + +class osc_proto : public QObject, public IProtocol +{ + Q_OBJECT + + osc_settings s; + QUdpSocket sock; + QHostAddress dest; + unsigned short port = 0; + +public: + osc_proto(); + module_status initialize() override; + void pose(const double *headpose, const double*) override; + QString game_name() override { return tr("Open Sound Control"); } +}; diff --git a/proto-osc/settings.hpp b/proto-osc/settings.hpp new file mode 100644 index 00000000..edeb45c6 --- /dev/null +++ b/proto-osc/settings.hpp @@ -0,0 +1,14 @@ +#pragma once +#include <QString> +#include "options/options.hpp" + +using namespace options; + +struct osc_settings : opts +{ + value<QString> address; + value<int> port; + osc_settings() : opts("proto-osc"), address{b, "address", "127.0.0.1"}, + port(b, "port", 53101) + {} +}; |