2 #include <AvndProcesses/AddressTools.hpp>
9 halp_meta(name,
"Pattern combiner")
10 halp_meta(author,
"ossia team")
11 halp_meta(category,
"Control/Data processing")
12 halp_meta(description,
"Apply an operation to all inputs matching a pattern")
13 halp_meta(c_name,
"avnd_pattern_combine")
14 halp_meta(uuid,
"18efe965-9acc-4703-9af3-3cef658b301a")
15 halp_meta(manual_url,
"https://ossia.io/score-docs/processes/pattern-combiner.html#pattern-combiner")
23 halp__enum(
"Mode", List, List, Average, Sum, Min, Max);
30 halp::val_port<
"Output", ossia::value> output;
33 std::vector<ossia::value> current_values;
37 int operator()(ossia::impulse)
const noexcept {
return 1; }
38 int operator()(
int)
const noexcept {
return 1; }
39 int operator()(
float)
const noexcept {
return 1; }
40 int operator()(
bool)
const noexcept {
return 1; }
41 int operator()(
const std::string&)
const noexcept {
return 1; }
42 int operator()(ossia::vec2f)
const noexcept {
return 2; }
43 int operator()(ossia::vec3f)
const noexcept {
return 3; }
44 int operator()(ossia::vec4f)
const noexcept {
return 4; }
45 int operator()(
const std::vector<ossia::value>& v)
const noexcept
50 operator()(
const std::vector<std::pair<std::string, ossia::value>>& v)
const noexcept
54 int operator()()
const noexcept {
return 0; }
57 static std::optional<ossia::val_type>
58 all_have_same_type(
const std::vector<ossia::value>& val) noexcept
63 auto t0 = val[0].get_type();
67 if(e.get_type() != t0)
69 if(e.apply(value_size{}) != n0)
79 static double map(
double res,
double other) noexcept {
return res = res + other; }
80 double reduce(
double res)
const noexcept
82 return res = res /
self.current_values.size();
88 static double map(
double res,
double other) noexcept {
return res = res + other; }
89 static double reduce(
double res) noexcept {
return res; }
94 static double map(
double res,
double other) noexcept
96 return res = std::min(res, other);
98 static double reduce(
double res) noexcept {
return res; }
103 static double map(
double res,
double other) noexcept
105 return res = std::max(res, other);
107 static double reduce(
double res) noexcept {
return res; }
110 void process_various(
auto func)
113 for(
const auto& val : current_values)
115 res = func.map(res, ossia::convert<double>(val));
117 res = func.reduce(res);
118 outputs.output.value = float(res);
121 template <
typename Op>
126 void operator()(ossia::impulse)
const noexcept { }
127 void operator()(
int)
const noexcept
130 for(
const auto& val :
self.current_values)
132 res = func.map(res,
float(*val.template target<int>()));
134 res = func.reduce(res);
135 self.outputs.output.value = res;
137 void operator()(
float)
const noexcept
140 for(
const auto& val :
self.current_values)
142 res = func.map(res, *val.template target<float>());
144 res = func.reduce(res);
145 self.outputs.output.value = res;
147 void operator()(
bool)
const noexcept
150 for(
const auto& val :
self.current_values)
152 res = func.map(res, (*val.template target<bool>() ? 1.f : 0.f));
154 res = func.reduce(res);
155 self.outputs.output.value = res;
157 void operator()(
const std::string&)
const noexcept { }
158 void operator()(ossia::vec2f)
const noexcept
161 for(
const auto& val :
self.current_values)
163 const auto& in = *val.template target<ossia::vec2f>();
164 res[0] = func.map(res[0], in[0]);
165 res[1] = func.map(res[1], in[1]);
167 res[0] = func.reduce(res[0]);
168 res[1] = func.reduce(res[1]);
169 self.outputs.output.value = res;
171 void operator()(ossia::vec3f)
const noexcept
174 for(
const auto& val :
self.current_values)
176 const auto& in = *val.template target<ossia::vec3f>();
177 res[0] = func.map(res[0], in[0]);
178 res[1] = func.map(res[1], in[1]);
179 res[2] = func.map(res[2], in[2]);
181 res[0] = func.reduce(res[0]);
182 res[1] = func.reduce(res[1]);
183 res[2] = func.reduce(res[2]);
184 self.outputs.output.value = res;
186 void operator()(ossia::vec4f)
const noexcept
189 for(
const auto& val :
self.current_values)
191 const auto& in = *val.template target<ossia::vec4f>();
192 res[0] = func.map(res[0], in[0]);
193 res[1] = func.map(res[1], in[1]);
194 res[2] = func.map(res[2], in[2]);
195 res[3] = func.map(res[3], in[3]);
197 res[0] = func.reduce(res[0]);
198 res[1] = func.reduce(res[1]);
199 res[2] = func.reduce(res[2]);
200 res[3] = func.reduce(res[3]);
201 self.outputs.output.value = res;
203 void operator()(
const std::vector<ossia::value>& v)
const noexcept
205 boost::container::small_vector<float, 250> res;
206 const int N = v.size();
208 for(
const auto& val :
self.current_values)
210 const auto& in = *val.template target<std::vector<ossia::value>>();
211 for(
int i = 0; i < N; i++)
213 res[i] = func.map(res[i], ossia::convert<float>(in[i]));
217 std::vector<ossia::value> rres;
218 for(
int i = 0; i < N; i++)
219 rres[i] = (
float)func.reduce(res[i]);
221 self.outputs.output.value = std::move(rres);
224 operator()(
const std::vector<std::pair<std::string, ossia::value>>& v)
const noexcept
227 void operator()()
const noexcept { }
230 template <
typename T>
231 void process_fixed(T func)
241 current_values.clear();
242 if(inputs.pattern.devices_dirty)
243 inputs.pattern.reprocess();
244 for(
auto in : this->roots)
246 if(
auto p = in->get_parameter())
247 current_values.push_back(p->value());
250 if(current_values.empty())
255 using mode = decltype(inputs.mode)::enum_type;
259 outputs.output.value = current_values;
261 case mode::Average: {
262 if(
auto t = all_have_same_type(current_values))
263 process_fixed(average{*
this});
265 process_various(average{*
this});
269 if(
auto t = all_have_same_type(current_values))
270 process_fixed(sum{*
this});
272 process_various(sum{*
this});
276 if(
auto t = all_have_same_type(current_values))
277 process_fixed(minimum{*
this});
279 process_various(minimum{*
this});
283 if(
auto t = all_have_same_type(current_values))
284 process_fixed(maximum{*
this});
286 process_various(maximum{*
this});