Skip to content

Commit

Permalink
ossia: work on making avnd objects support polyphonic controls
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Dec 9, 2024
1 parent a28f61b commit 40c1cee
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 35 deletions.
13 changes: 7 additions & 6 deletions include/avnd/binding/ossia/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,11 @@ class safe_node_base : public safe_node_base_base<T>
template <typename Functor, typename... Args>
void process_all_ports(Args&&... args)
{
int poly_instance = 0;
for(auto [impl, i, o] : this->impl.full_state())
{
static_assert(std::is_reference_v<decltype(impl)>);
Functor f{*this, impl, args...};
Functor f{*this, impl, poly_instance++, args...};
if constexpr(avnd::inputs_type<T>::size > 0)
process_inputs_impl(f, i);
if constexpr(avnd::outputs_type<T>::size > 0)
Expand Down Expand Up @@ -439,11 +440,11 @@ class safe_node_base : public safe_node_base_base<T>
if constexpr(time_controls::size > 0)
{
this->tempo = new_tempo;
time_controls::for_all_n2(
this->impl.inputs(),
[this, new_tempo](auto& field, auto pred_idx, auto f_idx) {
this->time_controls.set_tempo(this->impl, pred_idx, f_idx, new_tempo);
});
for(const auto& [eff, ins, outs] : this->impl.full_state())
time_controls::for_all_n2(
ins, [this, new_tempo](auto& field, auto pred_idx, auto f_idx) {
this->time_controls.set_tempo(this->impl, pred_idx, f_idx, new_tempo);
});
}
}

Expand Down
1 change: 1 addition & 0 deletions include/avnd/binding/ossia/port_run_postprocess.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct process_after_run
{
Exec_T& self;
Obj_T& impl;
int instance{};
int& start = self.start_frame_for_this_tick;
int& frames = self.frame_count_for_this_tick;

Expand Down
118 changes: 108 additions & 10 deletions include/avnd/binding/ossia/port_run_preprocess.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,129 @@
#include <ossia/dataflow/graph_node.hpp>
#include <ossia/dataflow/port.hpp>
#include <ossia/detail/math.hpp>
#include <ossia/detail/parse_relax.hpp>
#include <ossia/editor/curve/curve_segment/easing.hpp>
#include <ossia/network/value/format_value.hpp>

namespace oscr
{
template <typename Field, std::size_t Idx>
inline void update_value(
auto& node, auto& obj, Field& field, const ossia::value& src, auto& dst,
avnd::field_index<Idx> idx)

// If we have a polyphonic object
// And we get an array input that corresponds to the kind of data expected
// Then we apply the value element-wise to each monophonic instance
//
// To do this we must make sure that we always create as many "input" objects as needed
template <typename Value>
requires std::is_arithmetic_v<Value>
struct apply_value_polyphonic_control
{
if(node.from_ossia_value(field, src, dst, idx))
Value& res;
int instance;
bool operator()() const { return false; }
bool operator()(ossia::impulse) const
{
if_possible(field.update(obj));
if_possible(res = {});
return true;
}
}

bool operator()(float v) const
{
res = v;
return true;
}

bool operator()(int v) const
{
res = v;
return true;
}

bool operator()(bool v) const
{
res = v ? 1. : 0.;
return true;
}

bool operator()(const std::string& v) const
{
if(auto f = ossia::parse_relax<double>(v))
{
res = *f;
return true;
}
return false;
}

template <std::size_t N>
bool operator()(const std::array<float, N>& v) const
{
if(instance >= 0 && instance < N)
{
res = v[instance];
return true;
}
return false;
}
bool operator()(const std::vector<ossia::value>& v) const
{
if(instance >= 0 && instance < v.size())
{
res = ossia::convert<float>(v[instance]);
return true;
}
return false;
}
bool operator()(const ossia::value_map_type& v) const { return false; }
};

template <typename Exec_T, typename Obj_T>
struct process_before_run
{
Exec_T& self;
Obj_T& impl;
int instance{};
int start{};
int frames{};

template <typename Field, typename Value, std::size_t Idx>
OSSIA_INLINE void update_value(
Field& field, const ossia::value& src, Value& dst,
avnd::field_index<Idx> idx) const
{
// TODO
// if constexpr(oscr::real_good_mono_processor<Obj>)
if(self.from_ossia_value(field, src, dst, idx))
{
if_possible(field.update(impl));
}
}

// Some heads up for the most common cases, + handle mono deconstruction
template <typename Field, typename Value, std::size_t Idx>
requires std::is_arithmetic_v<Value>
OSSIA_INLINE void update_value(
Field& field, const ossia::value& src, Value& dst,
avnd::field_index<Idx> idx) const
{
// FIXME time controls & smooth
using eff_t = avnd::effect_container<Obj_T>;
static constexpr bool multi_instance = requires { sizeof(eff_t::multi_instance); };
if constexpr(
multi_instance && !avnd::smooth_parameter<Field> && !avnd::time_control<Field>)
{
if(src.apply(apply_value_polyphonic_control<Value>{dst, instance}))
{
if_possible(field.update(impl));
}
}
else
{
if(self.from_ossia_value(field, src, dst, idx))
{
if_possible(field.update(impl));
}
}
}
template <avnd::parameter Field, std::size_t Idx>
requires ossia_port<Field>
void init_value(Field& ctrl, auto& port, avnd::field_index<Idx> idx) const noexcept
Expand All @@ -60,7 +159,7 @@ struct process_before_run
if(!port.data.get_data().empty())
{
auto& last = port.data.get_data().back().value;
update_value(self, impl, ctrl, last, ctrl.value, idx);
update_value(ctrl, last, ctrl.value, idx);

if constexpr(avnd::control<Field>)
{
Expand Down Expand Up @@ -169,8 +268,7 @@ struct process_before_run
{
if(ts >= start && ts < start + frames)
{
update_value(
self, impl, ctrl, val, ctrl.values[ts - start], avnd::field_index<Idx>{});
update_value(ctrl, val, ctrl.values[ts - start], avnd::field_index<Idx>{});
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions include/avnd/binding/ossia/port_setup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ struct setup_variable_audio_ports
{
Exec_T& self;
Obj_T& impl;
int instance{};

using in_refl = avnd::audio_bus_input_introspection<Obj_T>;
using out_refl = avnd::audio_bus_output_introspection<Obj_T>;
Expand Down Expand Up @@ -549,6 +550,7 @@ struct setup_raw_ossia_ports
{
Exec_T& self;
Obj_T& impl;
int instance{};

template <ossia_port Field, std::size_t Idx>
void operator()(Field& ctrl, auto& port, avnd::field_index<Idx>) const noexcept
Expand Down
2 changes: 1 addition & 1 deletion include/avnd/binding/ossia/time_controls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ struct time_control_storage : time_control_input_storage<T>
for(auto state : t.full_state())
{
auto& port = avnd::pfr::get<NField>(state.inputs);
port.value = to_seconds(g.value, new_tempo);
port.value = to_seconds(g.value, new_tempo); // FIXME support multi-instance
if_possible(port.update(state.effect));
}
}
Expand Down
52 changes: 34 additions & 18 deletions include/avnd/wrappers/effect_container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,31 +298,40 @@ struct effect_container<T>
multi_instance
};

typename T::inputs inputs_storage;
struct state
{
T effect;
typename T::inputs inputs_storage;
};

std::vector<T> effect;
std::vector<state> effect;

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

auto& inputs() noexcept { return inputs_storage; }
auto& inputs() const noexcept { return inputs_storage; }
auto& outputs() noexcept { return dummy_instance; }
auto& outputs() const noexcept { return dummy_instance; }

struct ref
{
T& effect;
typename T::inputs& inputs;

[[no_unique_address]] avnd::dummy outputs;
};

ref full_state(int i) { return {effect[i], this->inputs_storage, dummy_instance}; }
ref full_state(int i)
{
return {effect[i].effect, effect[i].inputs_storage, dummy_instance};
}
full_state_iterator<effect_container> full_state()
{
return full_state_iterator<effect_container>{*this};
}

member_iterator<typename T::inputs> inputs()
{
for(auto& e : effect)
co_yield e.inputs_storage;
}
auto effects()
{
return member_iterator_poly_effect<effect_container>{*this};
Expand All @@ -339,21 +348,17 @@ struct effect_container<T>
multi_instance
};

typename T::inputs inputs_storage;

struct state
{
T effect;
typename T::inputs inputs_storage;
typename T::outputs outputs_storage;
};

std::vector<state> effect;

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

auto& inputs() noexcept { return inputs_storage; }
auto& inputs() const noexcept { return inputs_storage; }

struct ref
{
T& effect;
Expand All @@ -363,7 +368,7 @@ struct effect_container<T>

ref full_state(int i)
{
return {effect[i].effect, this->inputs_storage, effect[i].outputs_storage};
return {effect[i].effect, effect[i].inputs_storage, effect[i].outputs_storage};
}

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

member_iterator<typename T::inputs> inputs()
{
for(auto& e : effect)
co_yield e.inputs_storage;
}
member_iterator<typename T::outputs> outputs()
{
for(auto& e : effect)
Expand All @@ -393,19 +403,20 @@ struct effect_container<T>
multi_instance
};

typename T::inputs inputs_storage;
struct state
{
T effect;
typename T::inputs inputs_storage;
};

std::vector<T> effect;
std::vector<state> effect;

void init_channels(int input, int output)
{
assert(input == output);
effect.resize(input);
}

auto& inputs() noexcept { return inputs_storage; }
auto& inputs() const noexcept { return inputs_storage; }

struct ref
{
T& effect;
Expand All @@ -415,7 +426,7 @@ struct effect_container<T>

ref full_state(int i)
{
return {effect[i].effect, this->inputs_storage, effect[i].effect.outputs};
return {effect[i].effect, effect[i].inputs, effect[i].effect.outputs};
}

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

member_iterator<typename T::inputs> inputs()
{
for(auto& e : effect)
co_yield e.inputs_storage;
}
member_iterator<typename T::outputs> outputs()
{
for(auto& e : effect)
Expand Down

0 comments on commit 40c1cee

Please sign in to comment.