Skip to content

Commit b9a796c

Browse files
committed
ossia: work on making avnd objects support polyphonic controls
1 parent 59eb477 commit b9a796c

6 files changed

Lines changed: 153 additions & 35 deletions

File tree

include/avnd/binding/ossia/node.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,11 @@ class safe_node_base : public safe_node_base_base<T>
236236
template <typename Functor, typename... Args>
237237
void process_all_ports(Args&&... args)
238238
{
239+
int poly_instance = 0;
239240
for(auto [impl, i, o] : this->impl.full_state())
240241
{
241242
static_assert(std::is_reference_v<decltype(impl)>);
242-
Functor f{*this, impl, args...};
243+
Functor f{*this, impl, poly_instance++, args...};
243244
if constexpr(avnd::inputs_type<T>::size > 0)
244245
process_inputs_impl(f, i);
245246
if constexpr(avnd::outputs_type<T>::size > 0)
@@ -439,11 +440,11 @@ class safe_node_base : public safe_node_base_base<T>
439440
if constexpr(time_controls::size > 0)
440441
{
441442
this->tempo = new_tempo;
442-
time_controls::for_all_n2(
443-
this->impl.inputs(),
444-
[this, new_tempo](auto& field, auto pred_idx, auto f_idx) {
445-
this->time_controls.set_tempo(this->impl, pred_idx, f_idx, new_tempo);
446-
});
443+
for(const auto& [eff, ins, outs] : this->impl.full_state())
444+
time_controls::for_all_n2(
445+
ins, [this, new_tempo](auto& field, auto pred_idx, auto f_idx) {
446+
this->time_controls.set_tempo(this->impl, pred_idx, f_idx, new_tempo);
447+
});
447448
}
448449
}
449450

include/avnd/binding/ossia/port_run_postprocess.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct process_after_run
1919
{
2020
Exec_T& self;
2121
Obj_T& impl;
22+
int instance{};
2223
int& start = self.start_frame_for_this_tick;
2324
int& frames = self.frame_count_for_this_tick;
2425

include/avnd/binding/ossia/port_run_preprocess.hpp

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,129 @@
1616
#include <ossia/dataflow/graph_node.hpp>
1717
#include <ossia/dataflow/port.hpp>
1818
#include <ossia/detail/math.hpp>
19+
#include <ossia/detail/parse_relax.hpp>
1920
#include <ossia/editor/curve/curve_segment/easing.hpp>
2021
#include <ossia/network/value/format_value.hpp>
2122

2223
namespace oscr
2324
{
24-
template <typename Field, std::size_t Idx>
25-
inline void update_value(
26-
auto& node, auto& obj, Field& field, const ossia::value& src, auto& dst,
27-
avnd::field_index<Idx> idx)
25+
26+
// If we have a polyphonic object
27+
// And we get an array input that corresponds to the kind of data expected
28+
// Then we apply the value element-wise to each monophonic instance
29+
//
30+
// To do this we must make sure that we always create as many "input" objects as needed
31+
template <typename Value>
32+
requires std::is_arithmetic_v<Value>
33+
struct apply_value_polyphonic_control
2834
{
29-
if(node.from_ossia_value(field, src, dst, idx))
35+
Value& res;
36+
int instance;
37+
bool operator()() const { return false; }
38+
bool operator()(ossia::impulse) const
3039
{
31-
if_possible(field.update(obj));
40+
if_possible(res = {});
41+
return true;
3242
}
33-
}
43+
44+
bool operator()(float v) const
45+
{
46+
res = v;
47+
return true;
48+
}
49+
50+
bool operator()(int v) const
51+
{
52+
res = v;
53+
return true;
54+
}
55+
56+
bool operator()(bool v) const
57+
{
58+
res = v ? 1. : 0.;
59+
return true;
60+
}
61+
62+
bool operator()(const std::string& v) const
63+
{
64+
if(auto f = ossia::parse_relax<double>(v))
65+
{
66+
res = *f;
67+
return true;
68+
}
69+
return false;
70+
}
71+
72+
template <std::size_t N>
73+
bool operator()(const std::array<float, N>& v) const
74+
{
75+
if(instance >= 0 && instance < N)
76+
{
77+
res = v[instance];
78+
return true;
79+
}
80+
return false;
81+
}
82+
bool operator()(const std::vector<ossia::value>& v) const
83+
{
84+
if(instance >= 0 && instance < v.size())
85+
{
86+
res = ossia::convert<float>(v[instance]);
87+
return true;
88+
}
89+
return false;
90+
}
91+
bool operator()(const ossia::value_map_type& v) const { return false; }
92+
};
3493

3594
template <typename Exec_T, typename Obj_T>
3695
struct process_before_run
3796
{
3897
Exec_T& self;
3998
Obj_T& impl;
99+
int instance{};
40100
int start{};
41101
int frames{};
42102

103+
template <typename Field, typename Value, std::size_t Idx>
104+
OSSIA_INLINE void update_value(
105+
Field& field, const ossia::value& src, Value& dst,
106+
avnd::field_index<Idx> idx) const
107+
{
108+
// TODO
109+
// if constexpr(oscr::real_good_mono_processor<Obj>)
110+
if(self.from_ossia_value(field, src, dst, idx))
111+
{
112+
if_possible(field.update(impl));
113+
}
114+
}
115+
116+
// Some heads up for the most common cases, + handle mono deconstruction
117+
template <typename Field, typename Value, std::size_t Idx>
118+
requires std::is_arithmetic_v<Value>
119+
OSSIA_INLINE void update_value(
120+
Field& field, const ossia::value& src, Value& dst,
121+
avnd::field_index<Idx> idx) const
122+
{
123+
// FIXME time controls & smooth
124+
using eff_t = avnd::effect_container<Obj_T>;
125+
static constexpr bool multi_instance = requires { sizeof(eff_t::multi_instance); };
126+
if constexpr(
127+
multi_instance && !avnd::smooth_parameter<Field> && !avnd::time_control<Field>)
128+
{
129+
if(src.apply(apply_value_polyphonic_control<Value>{dst, instance}))
130+
{
131+
if_possible(field.update(impl));
132+
}
133+
}
134+
else
135+
{
136+
if(self.from_ossia_value(field, src, dst, idx))
137+
{
138+
if_possible(field.update(impl));
139+
}
140+
}
141+
}
43142
template <avnd::parameter Field, std::size_t Idx>
44143
requires ossia_port<Field>
45144
void init_value(Field& ctrl, auto& port, avnd::field_index<Idx> idx) const noexcept
@@ -60,7 +159,7 @@ struct process_before_run
60159
if(!port.data.get_data().empty())
61160
{
62161
auto& last = port.data.get_data().back().value;
63-
update_value(self, impl, ctrl, last, ctrl.value, idx);
162+
update_value(ctrl, last, ctrl.value, idx);
64163

65164
if constexpr(avnd::control<Field>)
66165
{
@@ -169,8 +268,7 @@ struct process_before_run
169268
{
170269
if(ts >= start && ts < start + frames)
171270
{
172-
update_value(
173-
self, impl, ctrl, val, ctrl.values[ts - start], avnd::field_index<Idx>{});
271+
update_value(ctrl, val, ctrl.values[ts - start], avnd::field_index<Idx>{});
174272
}
175273
}
176274
}

include/avnd/binding/ossia/port_setup.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ struct setup_variable_audio_ports
517517
{
518518
Exec_T& self;
519519
Obj_T& impl;
520+
int instance{};
520521

521522
using in_refl = avnd::audio_bus_input_introspection<Obj_T>;
522523
using out_refl = avnd::audio_bus_output_introspection<Obj_T>;
@@ -549,6 +550,7 @@ struct setup_raw_ossia_ports
549550
{
550551
Exec_T& self;
551552
Obj_T& impl;
553+
int instance{};
552554

553555
template <ossia_port Field, std::size_t Idx>
554556
void operator()(Field& ctrl, auto& port, avnd::field_index<Idx>) const noexcept

include/avnd/binding/ossia/time_controls.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ struct time_control_storage : time_control_input_storage<T>
5757
for(auto state : t.full_state())
5858
{
5959
auto& port = avnd::pfr::get<NField>(state.inputs);
60-
port.value = to_seconds(g.value, new_tempo);
60+
port.value = to_seconds(g.value, new_tempo); // FIXME support multi-instance
6161
if_possible(port.update(state.effect));
6262
}
6363
}

include/avnd/wrappers/effect_container.hpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -298,31 +298,40 @@ struct effect_container<T>
298298
multi_instance
299299
};
300300

301-
typename T::inputs inputs_storage;
301+
struct state
302+
{
303+
T effect;
304+
typename T::inputs inputs_storage;
305+
};
302306

303-
std::vector<T> effect;
307+
std::vector<state> effect;
304308

305309
void init_channels(int input, int output) { effect.resize(std::max(input, output)); }
306310

307-
auto& inputs() noexcept { return inputs_storage; }
308-
auto& inputs() const noexcept { return inputs_storage; }
309311
auto& outputs() noexcept { return dummy_instance; }
310312
auto& outputs() const noexcept { return dummy_instance; }
311313

312314
struct ref
313315
{
314316
T& effect;
315317
typename T::inputs& inputs;
316-
317318
[[no_unique_address]] avnd::dummy outputs;
318319
};
319320

320-
ref full_state(int i) { return {effect[i], this->inputs_storage, dummy_instance}; }
321+
ref full_state(int i)
322+
{
323+
return {effect[i].effect, effect[i].inputs_storage, dummy_instance};
324+
}
321325
full_state_iterator<effect_container> full_state()
322326
{
323327
return full_state_iterator<effect_container>{*this};
324328
}
325329

330+
member_iterator<typename T::inputs> inputs()
331+
{
332+
for(auto& e : effect)
333+
co_yield e.inputs_storage;
334+
}
326335
auto effects()
327336
{
328337
return member_iterator_poly_effect<effect_container>{*this};
@@ -339,21 +348,17 @@ struct effect_container<T>
339348
multi_instance
340349
};
341350

342-
typename T::inputs inputs_storage;
343-
344351
struct state
345352
{
346353
T effect;
354+
typename T::inputs inputs_storage;
347355
typename T::outputs outputs_storage;
348356
};
349357

350358
std::vector<state> effect;
351359

352360
void init_channels(int input, int output) { effect.resize(std::max(input, output)); }
353361

354-
auto& inputs() noexcept { return inputs_storage; }
355-
auto& inputs() const noexcept { return inputs_storage; }
356-
357362
struct ref
358363
{
359364
T& effect;
@@ -363,7 +368,7 @@ struct effect_container<T>
363368

364369
ref full_state(int i)
365370
{
366-
return {effect[i].effect, this->inputs_storage, effect[i].outputs_storage};
371+
return {effect[i].effect, effect[i].inputs_storage, effect[i].outputs_storage};
367372
}
368373

369374
full_state_iterator<effect_container> full_state()
@@ -376,6 +381,11 @@ struct effect_container<T>
376381
return member_iterator_poly_effect<effect_container>{*this};
377382
}
378383

384+
member_iterator<typename T::inputs> inputs()
385+
{
386+
for(auto& e : effect)
387+
co_yield e.inputs_storage;
388+
}
379389
member_iterator<typename T::outputs> outputs()
380390
{
381391
for(auto& e : effect)
@@ -393,19 +403,20 @@ struct effect_container<T>
393403
multi_instance
394404
};
395405

396-
typename T::inputs inputs_storage;
406+
struct state
407+
{
408+
T effect;
409+
typename T::inputs inputs_storage;
410+
};
397411

398-
std::vector<T> effect;
412+
std::vector<state> effect;
399413

400414
void init_channels(int input, int output)
401415
{
402416
assert(input == output);
403417
effect.resize(input);
404418
}
405419

406-
auto& inputs() noexcept { return inputs_storage; }
407-
auto& inputs() const noexcept { return inputs_storage; }
408-
409420
struct ref
410421
{
411422
T& effect;
@@ -415,7 +426,7 @@ struct effect_container<T>
415426

416427
ref full_state(int i)
417428
{
418-
return {effect[i].effect, this->inputs_storage, effect[i].effect.outputs};
429+
return {effect[i].effect, effect[i].inputs, effect[i].effect.outputs};
419430
}
420431

421432
full_state_iterator<effect_container> full_state()
@@ -428,6 +439,11 @@ struct effect_container<T>
428439
return member_iterator_poly_effect<effect_container>{*this};
429440
}
430441

442+
member_iterator<typename T::inputs> inputs()
443+
{
444+
for(auto& e : effect)
445+
co_yield e.inputs_storage;
446+
}
431447
member_iterator<typename T::outputs> outputs()
432448
{
433449
for(auto& e : effect)

0 commit comments

Comments
 (0)