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 <AvndProcesses/Alphanum.hpp>
8#include <halp/controls.hpp>
9#include <halp/meta.hpp>
10
11namespace 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
27struct 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