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