OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
detail/osc.hpp
1#pragma once
2#include <ossia/detail/parse_strict.hpp>
3#include <ossia/detail/string_view.hpp>
4#include <ossia/detail/to_string.hpp>
5#include <ossia/network/base/parameter.hpp>
6#include <ossia/network/common/value_bounding.hpp>
7#include <ossia/network/domain/domain.hpp>
8#include <ossia/network/osc/detail/osc_1_0_policy.hpp>
9#include <ossia/network/osc/detail/osc_fwd.hpp>
10#include <ossia/network/value/value.hpp>
11
12#include <oscpack/osc/OscOutboundPacketStream.h>
13#include <oscpack/osc/OscReceivedElements.h>
14namespace ossia::net
15{
16
17struct osc_utilities
18{
19 static float get_float(oscpack::ReceivedMessageArgumentIterator it, float f)
20 {
21 switch(it->TypeTag())
22 {
23 case oscpack::INT32_TYPE_TAG:
24 return it->AsInt32Unchecked();
25 case oscpack::INT64_TYPE_TAG:
26 return it->AsInt64Unchecked();
27 case oscpack::FLOAT_TYPE_TAG:
28 return it->AsFloatUnchecked();
29 case oscpack::DOUBLE_TYPE_TAG:
30 return it->AsDoubleUnchecked();
31 case oscpack::TIME_TAG_TYPE_TAG:
32 return it->AsTimeTagUnchecked();
33 case oscpack::CHAR_TYPE_TAG:
34 return it->AsCharUnchecked();
35 case oscpack::TRUE_TYPE_TAG:
36 return 1.f;
37 case oscpack::FALSE_TYPE_TAG:
38 return 0.f;
39 case oscpack::STRING_TYPE_TAG:
40 if(auto res = parse_strict<float>(it->AsStringUnchecked()))
41 return *res;
42 return f;
43 case oscpack::SYMBOL_TYPE_TAG:
44 if(auto res = parse_strict<float>(it->AsSymbolUnchecked()))
45 return *res;
46 return f;
47 default:
48 return f;
49 }
50 }
51
52 static int get_int(oscpack::ReceivedMessageArgumentIterator it, int i)
53 {
54 switch(it->TypeTag())
55 {
56 case oscpack::INT32_TYPE_TAG:
57 return it->AsInt32Unchecked();
58 case oscpack::INT64_TYPE_TAG:
59 return int32_t(it->AsInt64Unchecked());
60 case oscpack::FLOAT_TYPE_TAG:
61 return int32_t(it->AsFloatUnchecked());
62 case oscpack::DOUBLE_TYPE_TAG:
63 return int32_t(it->AsDoubleUnchecked());
64 case oscpack::TIME_TAG_TYPE_TAG:
65 return int32_t(it->AsTimeTagUnchecked());
66 case oscpack::CHAR_TYPE_TAG:
67 return int32_t(it->AsCharUnchecked());
68 case oscpack::TRUE_TYPE_TAG:
69 return 1;
70 case oscpack::FALSE_TYPE_TAG:
71 return 0;
72 case oscpack::STRING_TYPE_TAG:
73 if(auto res = parse_strict<int>(it->AsStringUnchecked()))
74 return *res;
75 return i;
76 case oscpack::SYMBOL_TYPE_TAG:
77 if(auto res = parse_strict<int>(it->AsSymbolUnchecked()))
78 return *res;
79 return i;
80 default:
81 return i;
82 }
83 }
84
85 static bool get_bool(oscpack::ReceivedMessageArgumentIterator it, bool b)
86 {
87 using namespace std::literals;
88 switch(it->TypeTag())
89 {
90 case oscpack::INT32_TYPE_TAG:
91 return it->AsInt32Unchecked();
92 case oscpack::INT64_TYPE_TAG:
93 return it->AsInt64Unchecked();
94 case oscpack::FLOAT_TYPE_TAG:
95 return it->AsFloatUnchecked();
96 case oscpack::DOUBLE_TYPE_TAG:
97 return it->AsDoubleUnchecked();
98 case oscpack::TIME_TAG_TYPE_TAG:
99 return it->AsTimeTagUnchecked();
100 case oscpack::CHAR_TYPE_TAG:
101 return it->AsCharUnchecked();
102 case oscpack::TRUE_TYPE_TAG:
103 return true;
104 case oscpack::FALSE_TYPE_TAG:
105 return false;
106 case oscpack::STRING_TYPE_TAG:
107 return (std::string_view(it->AsStringUnchecked()) == "1"sv);
108 case oscpack::SYMBOL_TYPE_TAG:
109 return (std::string_view(it->AsSymbolUnchecked()) == "1"sv);
110 default:
111 return b;
112 }
113 }
114
115 static char get_char(oscpack::ReceivedMessageArgumentIterator it, char c)
116 {
117 switch(it->TypeTag())
118 {
119 case oscpack::INT32_TYPE_TAG:
120 return char(it->AsInt32Unchecked());
121 case oscpack::INT64_TYPE_TAG:
122 return char(it->AsInt64Unchecked());
123 case oscpack::FLOAT_TYPE_TAG:
124 return char(it->AsFloatUnchecked());
125 case oscpack::DOUBLE_TYPE_TAG:
126 return char(it->AsDoubleUnchecked());
127 case oscpack::TIME_TAG_TYPE_TAG:
128 return char(it->AsTimeTagUnchecked());
129 case oscpack::CHAR_TYPE_TAG:
130 return char(it->AsCharUnchecked());
131 case oscpack::TRUE_TYPE_TAG:
132 return char{'T'};
133 case oscpack::FALSE_TYPE_TAG:
134 return char{'F'};
135 case oscpack::STRING_TYPE_TAG:
136 return char{it->AsStringUnchecked()[0]};
137 case oscpack::SYMBOL_TYPE_TAG:
138 return char{it->AsSymbolUnchecked()[0]};
139 default:
140 return c;
141 }
142 }
143
144 static std::string get_blob(oscpack::ReceivedMessageArgumentIterator it)
145 {
146 const void* data{};
147 oscpack::osc_bundle_element_size_t size{};
148 it->AsBlobUnchecked(data, size);
149 if(size > 0)
150 return std::string{(const char*)data, (std::size_t)size};
151 return std::string{};
152 }
153
154 static ossia::value create_value(oscpack::ReceivedMessageArgumentIterator it)
155 {
156 switch(it->TypeTag())
157 {
158 case oscpack::INT32_TYPE_TAG:
159 return int32_t{it->AsInt32Unchecked()};
160 case oscpack::INT64_TYPE_TAG:
161 return int32_t{(int)it->AsInt64Unchecked()};
162 case oscpack::FLOAT_TYPE_TAG:
163 return float{it->AsFloatUnchecked()};
164 case oscpack::DOUBLE_TYPE_TAG:
165 return float{(float)it->AsDoubleUnchecked()};
166 case oscpack::TIME_TAG_TYPE_TAG:
167 return int32_t(it->AsTimeTagUnchecked());
168 case oscpack::CHAR_TYPE_TAG:
169 return char{it->AsCharUnchecked()};
170 case oscpack::TRUE_TYPE_TAG:
171 return bool{true};
172 case oscpack::FALSE_TYPE_TAG:
173 return bool{false};
174 case oscpack::STRING_TYPE_TAG:
175 return std::string{it->AsStringUnchecked()};
176 case oscpack::SYMBOL_TYPE_TAG:
177 return std::string{it->AsSymbolUnchecked()};
178 case oscpack::BLOB_TYPE_TAG:
179 return get_blob(it);
180 case oscpack::RGBA_COLOR_TYPE_TAG: {
181 auto c = it->AsRgbaColorUnchecked();
182 return make_vec(
183 uint8_t(c >> 24 & 0xFF), uint8_t(c >> 16 & 0xFF), uint8_t(c >> 8 & 0xFF),
184 uint8_t(c & 0xFF));
185 }
186 default:
187 return ossia::impulse{};
188 }
189 }
190
191 static std::vector<ossia::value> create_list_(
192 oscpack::ReceivedMessageArgumentIterator& it,
193 oscpack::ReceivedMessageArgumentIterator& end)
194 {
195 std::vector<ossia::value> t;
196 for(; it != end; ++it)
197 {
198 switch(it->TypeTag())
199 {
200 case oscpack::INT32_TYPE_TAG:
201 t.emplace_back(int32_t{it->AsInt32Unchecked()});
202 break;
203 case oscpack::INT64_TYPE_TAG:
204 t.emplace_back(int32_t{(int)it->AsInt64Unchecked()});
205 break;
206 case oscpack::FLOAT_TYPE_TAG:
207 t.emplace_back(float{it->AsFloatUnchecked()});
208 break;
209 case oscpack::DOUBLE_TYPE_TAG:
210 t.emplace_back(float{(float)it->AsDoubleUnchecked()});
211 break;
212 case oscpack::TIME_TAG_TYPE_TAG:
213 t.emplace_back(int32_t(it->AsTimeTagUnchecked()));
214 break;
215 case oscpack::CHAR_TYPE_TAG:
216 t.emplace_back(char{it->AsCharUnchecked()});
217 break;
218 case oscpack::TRUE_TYPE_TAG:
219 t.emplace_back(bool{true});
220 break;
221 case oscpack::FALSE_TYPE_TAG:
222 t.emplace_back(bool{false});
223 break;
224 case oscpack::STRING_TYPE_TAG:
225 t.push_back(std::string{it->AsStringUnchecked()});
226 break;
227 case oscpack::SYMBOL_TYPE_TAG:
228 t.push_back(std::string{it->AsSymbolUnchecked()});
229 break;
230 case oscpack::BLOB_TYPE_TAG:
231 t.emplace_back(get_blob(it));
232 break;
233 case oscpack::RGBA_COLOR_TYPE_TAG: {
234 auto c = it->AsRgbaColorUnchecked();
235 t.emplace_back(make_vec(
236 uint8_t(c >> 24 & 0xFF), uint8_t(c >> 16 & 0xFF), uint8_t(c >> 8 & 0xFF),
237 uint8_t(c & 0xFF)));
238 break;
239 }
240 case oscpack::ARRAY_BEGIN_TYPE_TAG: {
241 ++it;
242 t.emplace_back(create_list_(it, end));
243 break;
244 }
245 case oscpack::ARRAY_END_TYPE_TAG: {
246 // don't call ++it here : it will be increased in the parent's
247 // for(....)
248 return t;
249 }
250 default:
251 t.push_back(ossia::impulse{});
252 break;
253 }
254 }
255 return t;
256 }
257
258 static std::vector<ossia::value> create_list(
259 oscpack::ReceivedMessageArgumentIterator it,
260 oscpack::ReceivedMessageArgumentIterator end)
261 {
262 return create_list_(it, end);
263 }
264
265 static ossia::value create_any(
266 oscpack::ReceivedMessageArgumentIterator cur_it,
267 oscpack::ReceivedMessageArgumentIterator end, int numArguments)
268 {
269 switch(numArguments)
270 {
271 case 0:
272 return ossia::impulse{};
273 case 1:
274 return create_value(cur_it);
275 default:
276 return value{create_list(cur_it, end)};
277 }
278 }
279};
280
281struct osc_inbound_visitor
282{
283 osc_inbound_visitor(
284 oscpack::ReceivedMessageArgumentIterator cur,
285 oscpack::ReceivedMessageArgumentIterator beg,
286 oscpack::ReceivedMessageArgumentIterator end, int n = 1)
287 : cur_it{cur}
288 , beg_it{beg}
289 , end_it{end}
290 , numArguments{n}
291 {
292 }
293
294 oscpack::ReceivedMessageArgumentIterator cur_it;
295 oscpack::ReceivedMessageArgumentIterator beg_it;
296 oscpack::ReceivedMessageArgumentIterator end_it;
297 int numArguments = 1;
298
299 ossia::value operator()(ossia::impulse imp) const { return imp; }
300
301 ossia::value operator()(int32_t i) const { return osc_utilities::get_int(cur_it, i); }
302
303 ossia::value operator()(float f) const { return osc_utilities::get_float(cur_it, f); }
304
305 ossia::value operator()(bool b) const { return osc_utilities::get_bool(cur_it, b); }
306
307 ossia::value operator()(char c) const { return osc_utilities::get_char(cur_it, c); }
308
309 ossia::value operator()(const std::string& str) const
310 {
311 switch(cur_it->TypeTag())
312 {
313 case oscpack::INT32_TYPE_TAG:
314 return ossia::to_string(cur_it->AsInt32Unchecked());
315 case oscpack::INT64_TYPE_TAG:
316 return ossia::to_string(cur_it->AsInt64Unchecked());
317 case oscpack::FLOAT_TYPE_TAG:
318 return ossia::to_string(cur_it->AsFloatUnchecked());
319 case oscpack::DOUBLE_TYPE_TAG:
320 return ossia::to_string(cur_it->AsDoubleUnchecked());
321 case oscpack::CHAR_TYPE_TAG:
322 return std::string(1, cur_it->AsCharUnchecked());
323 case oscpack::TRUE_TYPE_TAG:
324 return std::string{"true"};
325 case oscpack::FALSE_TYPE_TAG:
326 return std::string{"false"};
327 case oscpack::STRING_TYPE_TAG:
328 return std::string{cur_it->AsStringUnchecked()};
329 case oscpack::SYMBOL_TYPE_TAG:
330 return std::string{cur_it->AsSymbolUnchecked()};
331 default:
332 return str;
333 }
334 }
335
336 template <std::size_t N>
337 ossia::value operator()(std::array<float, N> vec) const
338 {
339 if(numArguments == N)
340 {
341 std::array<float, N> ret;
342 std::size_t i = 0;
343 auto vec_it = beg_it;
344 auto vec_end = end_it;
345 for(; vec_it != vec_end; ++vec_it)
346 {
347 ret[i] = osc_utilities::get_float(vec_it, vec[i]);
348 i++;
349 }
350 return ret;
351 }
352 else
353 {
354 if constexpr(N == 4)
355 {
356 if(cur_it->TypeTag() == oscpack::RGBA_COLOR_TYPE_TAG)
357 {
358 auto c = cur_it->AsRgbaColorUnchecked();
359 return make_vec(
360 uint8_t(c >> 24 & 0xFF), uint8_t(c >> 16 & 0xFF), uint8_t(c >> 8 & 0xFF),
361 uint8_t(c & 0xFF));
362 }
363 }
364 return vec;
365 }
366 }
367
368 ossia::value operator()(const std::vector<ossia::value>&)
369 {
370 /* This code preserves type info, this is not what we want.
371 int n = t.size();
372 if (numArguments == n)
373 {
374 for (int i = 0; i < n; i++)
375 {
376 auto res = ossia::apply_nonnull(*this, t[i].v);
377 t[i] = std::move(res);
378 ++cur_it;
379 }
380 }
381 */
382 return value{osc_utilities::create_list(cur_it, end_it)};
383 }
384
385 ossia::value operator()(const value_map_type&) { return value{value_map_type{}}; }
386
387 ossia::value operator()() const { return {}; }
388};
389
390struct osc_inbound_impulse_visitor
391{
392 // If our address is any type, e.g. float, etc., we treat an "empty" message as a bang on it
393 template <typename T>
394 ossia::value operator()(T&& t) const
395 {
396 return ossia::value{std::forward<T>(t)};
397 }
398
399 // If the address is a list otoh, it means that we're getting an empty list
400 ossia::value operator()(const std::vector<ossia::value>& t) const
401 {
402 return ossia::value{std::vector<ossia::value>{}};
403 }
404
405 ossia::value operator()() const { return {}; }
406};
407
409 const ossia::value& current, oscpack::ReceivedMessageArgumentIterator beg_it,
410 oscpack::ReceivedMessageArgumentIterator end_it, int N)
411{
412 if(beg_it != end_it)
413 return current.apply(osc_inbound_visitor{beg_it, beg_it, end_it, N});
414 else
415 return current.apply(osc_inbound_impulse_visitor{});
416}
417
418inline ossia::value get_filtered_value(
419 ossia::net::parameter_base& addr, oscpack::ReceivedMessageArgumentIterator beg_it,
420 oscpack::ReceivedMessageArgumentIterator end_it, int N)
421{
422 return bound_value(
423 addr.get_domain(), ossia::net::to_value(addr.value(), beg_it, end_it, N),
424 addr.get_bounding());
425}
426
427inline ossia::value get_filtered_value(
428 ossia::net::parameter_base& addr, const oscpack::ReceivedMessage& mess)
429{
430 return get_filtered_value(
431 addr, mess.ArgumentsBegin(), mess.ArgumentsEnd(), mess.ArgumentCount());
432}
433
434struct osc_write_domain_visitor
435{
436 ossia::net::osc_1_0_outbound_stream_visitor vis;
437 template <typename T>
438 void operator()(const T& dom)
439 {
440 if(dom.min && dom.max)
441 {
442 vis(*dom.min);
443 vis(*dom.max);
444 }
445 }
446
447 template <std::size_t N>
448 void operator()(const vecf_domain<N>& dom)
449 {
450 if(dom.min[0] && dom.max[0])
451 {
452 vis(*dom.min[0]);
453 vis(*dom.max[0]);
454 }
455 }
456
457 void operator()(const vector_domain& dom)
458 {
459 if(!dom.min.empty() && !dom.max.empty() && dom.min[0].valid() && dom.max[0].valid())
460 {
461 vis(ossia::convert<float>(dom.min[0]));
462 vis(ossia::convert<float>(dom.max[0]));
463 }
464 }
465
466 void operator()(const domain_base<ossia::value>& dom)
467 {
468 if(dom.min && dom.max)
469 {
470 vis(ossia::convert<float>(*dom.min));
471 vis(ossia::convert<float>(*dom.max));
472 }
473 }
474
475 void operator()(const domain_base<bool>& dom)
476 {
477 vis(false);
478 vis(true);
479 }
480
481 void operator()(const domain_base<ossia::impulse>& dom) { }
482
483 void operator()(const domain_base<std::string>& dom) { }
484
485 void operator()() { }
486};
487}
488
489namespace oscpack
490{
491/*
492inline oscpack::OutboundPacketStream&
493operator<<(oscpack::OutboundPacketStream& p, const ossia::value& val)
494{
495 val.apply(ossia::net::osc_outbound_visitor{p});
496 return p;
497}
498*/
499
500inline oscpack::OutboundPacketStream&
501operator<<(oscpack::OutboundPacketStream& p, const ossia::domain& dom)
502{
503 ossia::apply(
504 ossia::net::osc_write_domain_visitor{
505 ossia::net::osc_1_0_outbound_stream_visitor{p, ossia::unit_t{}}},
506 dom);
507
508 return p;
509}
510}
The parameter_base class.
Definition ossia/network/base/parameter.hpp:48
virtual ossia::value value() const =0
Clone the current value without any network request.
The value class.
Definition value.hpp:173
value to_value(const value_with_unit &v)
convert Convert a value + unit to a simple value
Definition dataspace_visitors.cpp:232
domain A domain of values
Definition domain_base.hpp:23
Definition dataspace.hpp:24