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