OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
ossia-qt/protocols/utils.hpp
1#pragma once
2#include <ossia/network/osc/detail/osc_value_write_visitor.hpp>
3#include <ossia/network/sockets/encoding.hpp>
4#include <ossia/network/osc/detail/osc_packet_processor.hpp>
5#include <ossia/network/sockets/writers.hpp>
6
7#include <ossia-qt/invoke.hpp>
8#include <ossia-qt/js_utilities.hpp>
9
10#include <boost/asio/io_context.hpp>
11
12#include <QPointer>
13#include <QJSEngine>
14
15#define run_on_qt_thread(...) \
16 ossia::qt::run_async(this, [=, this] { __VA_ARGS__; }, Qt::AutoConnection);
17#define run_on_asio_thread(...) \
18 boost::asio::dispatch(this->context(), [=, self = QPointer{this}] { __VA_ARGS__ });
19
20namespace ossia::qt
21{
22struct buffer_writer
23{
24 QByteArray& buffer;
25 void operator()(const char* data, std::size_t sz) const
26 {
27 buffer.append(data, sz);
28 }
29};
30
31inline QByteArray
32apply_encoding(ossia::net::encoding enc, const QByteArray& data)
33{
34 if(enc == ossia::net::encoding::none)
35 return data;
36 QByteArray out(int(ossia::net::max_encoded_size(enc, data.size())), '\0');
37 auto actual = ossia::net::encode_to(enc, data.data(), data.size(), out.data());
38 out.resize(int(actual));
39 return out;
40}
41
42inline QByteArray
43apply_decoding(ossia::net::encoding enc, const unsigned char* data, std::size_t sz)
44{
45 if(enc == ossia::net::encoding::none)
46 return QByteArray((const char*)data, sz);
47 QByteArray out(int(ossia::net::max_decoded_size(enc, sz)), '\0');
48 auto actual = ossia::net::decode_to(enc, (const char*)data, sz, out.data());
49 out.resize(int(actual));
50 return out;
51}
52
53inline QByteArray
54apply_decoding(ossia::net::encoding enc, const char* data, std::size_t sz)
55{
56 if(enc == ossia::net::encoding::none)
57 return QByteArray(data, sz);
58 QByteArray out(int(ossia::net::max_decoded_size(enc, sz)), '\0');
59 auto actual = ossia::net::decode_to(enc, data, sz, out.data());
60 out.resize(int(actual));
61 return out;
62}
63
64struct protocols_sender
65{
66 void send_osc(this auto&& self, QByteArray address, const QJSValueList& values)
67 {
68 auto& sock = *self.socket;
69 using socket_type = std::remove_cvref_t<decltype(sock)>;
70 using writer_type = ossia::net::socket_writer<socket_type>;
71 using send_visitor = ossia::net::osc_value_send_visitor<
72 ossia::net::full_parameter_data, ossia::net::osc_1_0_policy, writer_type>;
73
75 const std::string addr = address.toStdString();
76
77 switch(values.size())
78 {
79 case 0: {
80 ossia::value{ossia::impulse{}}.apply(
81 send_visitor{p, addr, writer_type{sock}});
82 break;
83 }
84 case 1: {
85 auto v = ossia::qt::value_from_js(values[0]);
86 v.apply(send_visitor{p, addr, writer_type{sock}});
87 break;
88 }
89 default: {
90 std::vector<ossia::value> vec;
91 vec.reserve(values.size());
92 for(const auto& v : values)
93 vec.push_back(ossia::qt::value_from_js(v));
94 ossia::value vvec(std::move(vec));
95 vvec.apply(send_visitor{p, addr, writer_type{sock}});
96 }
97 }
98 }
99};
100
101class qml_osc_processor : public QObject
102{
103 W_OBJECT(qml_osc_processor)
104public:
105 explicit qml_osc_processor() { }
106
107 QJSValue onOsc;
108
109 void processMessage(const QByteArray& bv)
110 {
111 if(onOsc.isCallable())
112 {
113 ossia::net::osc_packet_processor<decltype(*this)> processor{*this};
114 processor(bv.data(), bv.size());
115 }
116 }
117 W_SLOT(processMessage)
118
119 void operator()(const oscpack::ReceivedMessage& msg)
120 {
121 QString address = QString::fromUtf8(msg.AddressPattern());
122
123 QJSValueList values;
124 auto* engine = qjsEngine(this);
125 if(!engine)
126 return;
127
128 for(auto it = msg.ArgumentsBegin(); it != msg.ArgumentsEnd(); ++it)
129 values.append(oscArgToQJSValue(*it, *engine));
130
131 onOsc.call({engine->toScriptValue(address), engine->toScriptValue(values)});
132 }
133
134 static QJSValue
135 oscArgToQJSValue(const oscpack::ReceivedMessageArgument& arg, QJSEngine& engine)
136 {
137 switch(arg.TypeTag())
138 {
139 case oscpack::INT32_TYPE_TAG:
140 return QJSValue(arg.AsInt32Unchecked());
141 case oscpack::INT64_TYPE_TAG:
142 return QJSValue((int)arg.AsInt64Unchecked());
143 case oscpack::FLOAT_TYPE_TAG:
144 return QJSValue(arg.AsFloatUnchecked());
145 case oscpack::DOUBLE_TYPE_TAG:
146 return QJSValue(arg.AsDoubleUnchecked());
147 case oscpack::TIME_TAG_TYPE_TAG:
148 return QJSValue((int)arg.AsTimeTagUnchecked());
149 case oscpack::CHAR_TYPE_TAG:
150 return QJSValue(QString(QChar(arg.AsCharUnchecked())));
151 case oscpack::TRUE_TYPE_TAG:
152 return QJSValue(true);
153 case oscpack::FALSE_TYPE_TAG:
154 return QJSValue(false);
155 case oscpack::STRING_TYPE_TAG:
156 return QJSValue(QString::fromUtf8(arg.AsStringUnchecked()));
157 case oscpack::SYMBOL_TYPE_TAG:
158 return QJSValue(QString::fromUtf8(arg.AsSymbolUnchecked()));
159 case oscpack::BLOB_TYPE_TAG: {
160 const void* data{};
161 oscpack::osc_bundle_element_size_t size{};
162 arg.AsBlobUnchecked(data, size);
163 QByteArray blob((const char*)data, size);
164 return engine.toScriptValue(blob);
165 }
166 case oscpack::RGBA_COLOR_TYPE_TAG: {
167 auto c = arg.AsRgbaColorUnchecked();
168 auto array = engine.newArray(4);
169 array.setProperty(0, uint8_t(c >> 24 & 0xFF));
170 array.setProperty(1, uint8_t(c >> 16 & 0xFF));
171 array.setProperty(2, uint8_t(c >> 8 & 0xFF));
172 array.setProperty(3, uint8_t(c & 0xFF));
173 return array;
174 }
175 default:
176 return QJSValue(QJSValue::NullValue);
177 }
178 }
179};
180}
The value class.
Definition value.hpp:173
Definition qml_device.cpp:43
Definition git_info.h:7
Full information about a parameter.
Definition parameter_data.hpp:61