OSSIA
Open Scenario System for Interactive Application
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>
14 namespace ossia::net
15 {
16 
17 struct 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 
281 struct 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 
390 struct 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 
408 inline ossia::value to_value(
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 
418 inline 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 
427 inline 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 
434 struct 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 
489 namespace oscpack
490 {
491 /*
492 inline oscpack::OutboundPacketStream&
493 operator<<(oscpack::OutboundPacketStream& p, const ossia::value& val)
494 {
495  val.apply(ossia::net::osc_outbound_visitor{p});
496  return p;
497 }
498 */
499 
500 inline oscpack::OutboundPacketStream&
501 operator<<(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