OSSIA
Open Scenario System for Interactive Application
osc_receive.hpp
1 #pragma once
2 #include <ossia/detail/fmt.hpp>
4 #include <ossia/network/base/device.hpp>
5 #include <ossia/network/base/listening.hpp>
6 #include <ossia/network/base/message_origin_identifier.hpp>
7 #include <ossia/network/base/parameter.hpp>
8 #include <ossia/network/common/network_logger.hpp>
9 #include <ossia/network/osc/detail/osc.hpp>
10 
11 #include <oscpack/osc/OscPrintReceivedElements.h>
12 #include <oscpack/osc/OscReceivedElements.h>
13 
14 #if defined(OSSIA_HAS_FMT)
15 namespace fmt
16 {
17 template <>
18 struct formatter<oscpack::ReceivedMessage>
19 {
20  template <typename ParseContext>
21  constexpr auto parse(ParseContext& ctx)
22  {
23  return ctx.begin();
24  }
25 
26  template <typename FormatContext>
27  auto format(const oscpack::ReceivedMessage& m, FormatContext& ctx)
28  {
29  auto out = ctx.out();
30  out = fmt::format_to(out, "{}", m.AddressPattern());
31  if(m.ArgumentCount() > 0)
32  {
33  out = fmt::format_to(out, ": ");
34  auto buf = fmt::basic_memory_buffer<char>();
35  for(auto it = m.ArgumentsBegin(); it != m.ArgumentsEnd(); ++it)
36  {
37  using namespace detail;
38  buf.clear();
39 
40  formatbuf<std::basic_streambuf<char>> format_buf{buf};
41  std::basic_ostream<char> output{&format_buf};
42  output << *it;
43 
44  out = fmt::format_to(out, "{} ", std::string_view{buf.data(), buf.size()});
45  }
46  }
47  return ctx.out();
48  }
49 };
50 }
51 #endif
52 
53 namespace ossia::net
54 {
55 
56 struct osc_message_applier
57 {
58  message_origin_identifier id;
59  const oscpack::ReceivedMessage& m;
60  void on_listened_value(
62  network_logger& logger)
63  {
64  if(auto v = net::get_filtered_value(the_addr, m); v.valid())
65  {
66  dev.apply_incoming_message(id, the_addr, std::move(v));
67  }
68 
69  if(logger.inbound_listened_logger)
70  logger.inbound_listened_logger->info("[input] {}", m);
71  }
72 
73  void on_value(ossia::net::parameter_base& the_addr, ossia::net::device_base& dev)
74  {
75  if(auto v = net::get_filtered_value(the_addr, m); v.valid())
76  {
77  dev.apply_incoming_message(id, the_addr, std::move(v));
78  }
79  }
80 
81  void on_value_quiet(ossia::net::parameter_base& the_addr, ossia::net::device_base& dev)
82  {
83  if(auto v = net::get_filtered_value(the_addr, m); v.valid())
84  {
85  dev.apply_incoming_message_quiet(id, the_addr, std::move(v));
86  }
87  }
88 
89  void on_unhandled(ossia::net::device_base& dev)
90  {
91  dev.on_unhandled_message(
92  m.AddressPattern(),
93  net::osc_utilities::create_any(
94  m.ArgumentsBegin(), m.ArgumentsEnd(), m.ArgumentCount()));
95  }
96 
97  void log(network_logger& logger)
98  {
99  if(logger.inbound_logger)
100  logger.inbound_logger->info("[input] {}", m);
101  }
102 };
103 
104 template <bool SilentUpdate, typename F>
105 void on_input_message(
106  std::string_view addr_txt, F&& f, const ossia::net::listened_parameters& listening,
107  ossia::net::device_base& dev, network_logger& logger)
108 {
109  auto addr = listening.find(addr_txt);
110 
111  if(addr && *addr)
112  {
113  f.on_listened_value(**addr, dev, logger);
114  }
115  else
116  {
117  // We still want to save the value even if it is not listened to.
118  if(auto n = find_node(dev.get_root_node(), addr_txt))
119  {
120  if(auto base_addr = n->get_parameter())
121  {
122  if constexpr(!SilentUpdate)
123  f.on_value(*base_addr, dev);
124  else
125  f.on_value_quiet(*base_addr, dev);
126  }
127  }
128  else
129  {
130  // Try to handle pattern matching
131  auto nodes = find_nodes(dev.get_root_node(), addr_txt);
132  for(auto n : nodes)
133  {
134  if(auto addr = n->get_parameter())
135  {
136  if(!SilentUpdate || listening.find(n->osc_address()))
137  f.on_value(*addr, dev);
138  else
139  f.on_value_quiet(*addr, dev);
140  }
141  }
142 
143  if(nodes.empty())
144  f.on_unhandled(dev);
145  }
146  }
147 
148  f.log(logger);
149 }
150 
151 }
Root of a device tree.
Definition: ossia/network/base/device.hpp:58
The parameter_base class.
Definition: ossia/network/base/parameter.hpp:48
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition: context.cpp:104
OSSIA_EXPORT ossia::net::node_base * find_node(node_base &dev, std::string_view parameter_base)
Find a node in a device.
OSSIA_EXPORT std::vector< ossia::net::node_base * > find_nodes(node_base &dev, std::string_view pattern)
Find all nodes matching a pattern in a device.