AddressTools.hpp
1 #pragma once
2 #include <ossia/dataflow/exec_state_facade.hpp>
3 #include <ossia/dataflow/execution_state.hpp>
4 #include <ossia/detail/algorithms.hpp>
5 #include <ossia/network/common/path.hpp>
6 
7 #include <halp/controls.hpp>
8 #include <halp/meta.hpp>
9 
10 namespace avnd_tools
11 {
12 
13 // Given:
14 // address: /foo.*/value
15 // -> /foo.1/value, /foo.2/value, etc.
16 // input: [1, 34, 6, 4]
17 // -> writes 1 on foo.1/value, 34 on foo.2/value, etc
18 
20 {
21  ossia::exec_state_facade ossia_state;
22  std::optional<ossia::traversal::path> m_path;
23  std::vector<ossia::net::node_base*> roots;
24 };
25 
26 struct PatternSelector : halp::lineedit<"Pattern", "">
27 {
28  void update(PatternObject& p)
29  {
30  current_object = &p;
31  if(!p.ossia_state.impl)
32  return;
33  if(value.empty())
34  {
35  p.m_path = {};
36  p.roots.clear();
37  return;
38  }
39 
40  p.m_path = ossia::traversal::make_path(value);
41  reprocess();
42  }
43 
44  void reprocess()
45  {
46  if(!current_object)
47  return;
48 
49  auto& p = *current_object;
50  ossia::execution_state& st = *p.ossia_state.impl;
51  const auto& rdev = st.exec_devices();
52  p.roots.clear();
53 
54  if(!p.m_path)
55  return;
56 
57  for(auto& dev : rdev)
58  {
59  if(devices_observed.find(dev) == devices_observed.end())
60  {
61  devices_observed.insert(dev);
62  dev->on_node_created.connect<&PatternSelector::mark_dirty>(this);
63  dev->on_node_removing.connect<&PatternSelector::mark_dirty>(this);
64  }
65  p.roots.push_back(&dev->get_root_node());
66  }
67 
68  for(auto it = devices_observed.begin(); it != devices_observed.end();)
69  {
70  if(!ossia::contains(rdev, *it))
71  it = devices_observed.erase(it);
72  else
73  ++it;
74  }
75 
76  ossia::traversal::apply(*p.m_path, p.roots);
77  devices_dirty = false;
78  }
79 
81  {
82  reprocess();
83  for(auto* dev : devices_observed)
84  {
85  dev->on_node_created.disconnect<&PatternSelector::mark_dirty>(this);
86  dev->on_node_removing.disconnect<&PatternSelector::mark_dirty>(this);
87  }
88  }
89 
90  void mark_dirty(ossia::net::node_base&) { devices_dirty = true; }
91 
92  PatternObject* current_object{};
93  bool devices_dirty = false;
94 
95  ossia::flat_set<ossia::net::device_base*> devices_observed;
96 };
97 
99 {
100  halp_meta(name, "Pattern applier")
101  halp_meta(author, "ossia team")
102  halp_meta(category, "Control/Data processing")
103  halp_meta(description, "Send a message to all nodes matching a pattern")
104  halp_meta(c_name, "avnd_pattern_apply")
105  halp_meta(uuid, "44a55ee1-c2c9-43d5-a655-8eaedaff394c")
106 
107  struct
108  {
109  halp::val_port<"Input", ossia::value> input;
110  PatternSelector pattern;
111  } inputs;
112 
113  struct
114  {
115 
116  } outputs;
117 
118  void operator()()
119  {
120  if(!m_path)
121  return;
122 
123  auto process = [this](const std::vector<ossia::value>& vec) {
124  const auto N = std::min(roots.size(), vec.size());
125  for(std::size_t i = 0; i < N; i++)
126  {
127  if(auto p = roots[i]->get_parameter())
128  {
129  p->push_value(vec[i]);
130  }
131  }
132  };
133 
134  if(auto vvec = inputs.input.value.target<std::vector<ossia::value>>())
135  {
136  process(*vvec);
137  }
138  else
139  {
140  process(ossia::convert<std::vector<ossia::value>>(inputs.input.value));
141  }
142  }
143 };
144 }
Definition: AddressTools.hpp:20
Definition: AddressTools.hpp:27
Definition: AddressTools.hpp:99