Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions examples/Raw/Interpolator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ struct ExponentialSmoothing
static constexpr auto description() { return "Simplest real-time value smoothing"; }
static constexpr auto uuid() { return "971739ae-14a3-4283-b0a0-96dbd367ce66"; }

struct
// Allows the object to be seen as a value, not audio, processor
enum
{
struct
{
static constexpr auto name() { return "Input"; }
double value{};
} in;
cv
};

struct
{
struct
{
static constexpr auto name() { return "Alpha"; }
Expand All @@ -38,21 +38,15 @@ struct ExponentialSmoothing

struct
{
struct
{
static constexpr auto name() { return "Output"; }
double value{};
} out;
} outputs;

double filtered{};
void operator()()
double operator()(double in)
{
const double in = this->inputs.in.value;
const double a = this->inputs.alpha.value;

filtered = in * a + filtered * (1.0f - a);
outputs.out.value = filtered;
return filtered;
}
};
}
88 changes: 50 additions & 38 deletions include/avnd/binding/ossia/data_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace oscr

// Special case for the easy non-audio case
template <ossia_compatible_nonaudio_processor T>
requires(!(avnd::tag_cv<T> && avnd::tag_stateless<T>))
requires(!avnd::tag_cv<T>)
class safe_node<T> : public safe_node_base<T, safe_node<T>>
{
public:
Expand Down Expand Up @@ -49,7 +49,7 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
};

template <ossia_compatible_nonaudio_processor T>
requires(avnd::tag_cv<T> && avnd::tag_stateless<T>)
requires(avnd::tag_cv<T>)
class safe_node<T> : public safe_node_base<T, safe_node<T>>
{
public:
Expand All @@ -60,8 +60,27 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
constexpr bool scan_audio_input_channels() { return false; }
// This function goes from a host-provided tick to what the plugin expects
template <typename Tick>
static auto invoke_effect(T& obj, auto&& val, const Tick& t)
auto invoke_effect(int index, int N, auto&& val, const Tick& t)
{
T* pobj{};
if constexpr(avnd::tag_stateless<T>)
{
pobj = &this->impl.effect;
}
else
{
this->impl.effect.reserve(N);
while(this->impl.effect.size() < N)
{
// FIXME this should be done before prepare, port copy, etc
if(this->impl.effect.empty())
this->impl.effect.resize(1);
else
this->impl.effect.push_back(this->impl.effect[0]);
}
pobj = &this->impl.effect[index];
}
auto& obj = *pobj;
// clang-format off
if constexpr(std::is_integral_v<Tick>)
{
Expand Down Expand Up @@ -102,37 +121,35 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
const Tick& tick;
int ts{};
void operator()() { }
void operator()(ossia::impulse) { self.invoke_effect(self.impl.effect, 0, tick); }
void operator()(bool v) { self.invoke_effect(self.impl.effect, v ? 1 : 0, tick); }
void operator()(int v) { self.invoke_effect(self.impl.effect, v, tick); }
void operator()(float v) { self.invoke_effect(self.impl.effect, v, tick); }
void operator()(ossia::impulse) { self.invoke_effect(0, 1, 0, tick); }
void operator()(bool v) { self.invoke_effect(0, 1, v ? 1 : 0, tick); }
void operator()(int v) { self.invoke_effect(0, 1, v, tick); }
void operator()(float v) { self.invoke_effect(0, 1, v, tick); }
void operator()(const std::string& v)
{
self.invoke_effect(self.impl.effect, std::stof(v), tick);
self.invoke_effect(0, 1, std::stof(v), tick);
}
template <std::size_t N>
void operator()(std::array<float, N> v)
{
std::array<float, N> res;
for(int i = 0; i < N; i++)
res[i] = self.invoke_effect(self.impl.effect, v[i], tick);
res[i] = self.invoke_effect(i, N, v[i], tick);
}

// FIXME handle recursion
void operator()(const std::vector<ossia::value>& v)
{
std::vector<ossia::value> res;
res.reserve(v.size());

for(std::size_t i = 0; i < v.size(); i++)
self.invoke_effect(self.impl.effect, ossia::convert<float>(v[i]), tick);
for(std::size_t i = 0, N = v.size(); i < N; i++)
self.invoke_effect(i, N, ossia::convert<float>(v[i]), tick);
}
void operator()(const ossia::value_map_type& v)
{
ossia::value_map_type res;
int N = v.size();
int i = 0;
for(auto& [k, val] : v)
{
self.invoke_effect(self.impl.effect, ossia::convert<float>(val), tick);
self.invoke_effect(i++, N, ossia::convert<float>(val), tick);
}
}
};
Expand All @@ -147,30 +164,24 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
void operator()() { }
void operator()(ossia::impulse)
{
out.write_value(self.invoke_effect(self.impl.effect, 0, tick), 0);
out.write_value(self.invoke_effect(0, 1, 0, tick), 0);
}
void operator()(bool v)
{
out.write_value(self.invoke_effect(self.impl.effect, v ? 1 : 0, tick), 0);
}
void operator()(int v)
{
out.write_value(self.invoke_effect(self.impl.effect, v, tick), 0);
}
void operator()(float v)
{
out.write_value(self.invoke_effect(self.impl.effect, v, tick), 0);
out.write_value(self.invoke_effect(0, 1, v ? 1 : 0, tick), 0);
}
void operator()(int v) { out.write_value(self.invoke_effect(0, 1, v, tick), 0); }
void operator()(float v) { out.write_value(self.invoke_effect(0, 1, v, tick), 0); }
void operator()(const std::string& v)
{
out.write_value(self.invoke_effect(self.impl.effect, std::stof(v), tick), 0);
out.write_value(self.invoke_effect(0, 1, std::stof(v), tick), 0);
}
template <std::size_t N>
void operator()(std::array<float, N> v)
{
std::array<float, N> res;
for(int i = 0; i < N; i++)
res[i] = self.invoke_effect(self.impl.effect, v[i], tick);
res[i] = self.invoke_effect(i, N, v[i], tick);
out.write_value(res, 0);
}

Expand All @@ -180,19 +191,20 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
std::vector<ossia::value> res;
res.reserve(v.size());

for(std::size_t i = 0; i < v.size(); i++)
res.push_back(
self.invoke_effect(self.impl.effect, ossia::convert<float>(v[i]), tick));
for(std::size_t i = 0, N = v.size(); i < N; i++)
res.push_back(self.invoke_effect(i, N, ossia::convert<ValType>(v[i]), tick));

out.write_value(std::move(res), 0);
}
void operator()(const ossia::value_map_type& v)
{
int N = v.size();
int i = 0;
ossia::value_map_type res;
for(auto& [k, val] : v)
{
res.emplace_back(
k, self.invoke_effect(self.impl.effect, ossia::convert<float>(val), tick));
k, self.invoke_effect(i++, N, ossia::convert<ValType>(val), tick));
}
out.write_value(std::move(res), 0);
}
Expand All @@ -208,27 +220,27 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
void operator()() { }
void operator()(ossia::impulse)
{
if(auto res = self.invoke_effect(self.impl.effect, 0, tick))
if(auto res = self.invoke_effect(0, 1, 0, tick))
out.write_value(*res, 0);
}
void operator()(bool v)
{
if(auto res = self.invoke_effect(self.impl.effect, v ? 1 : 0, tick))
if(auto res = self.invoke_effect(0, 1, v ? 1 : 0, tick))
out.write_value(*res, 0);
}
void operator()(int v)
{
if(auto res = self.invoke_effect(self.impl.effect, v, tick))
if(auto res = self.invoke_effect(0, 1, v, tick))
out.write_value(*res, 0);
}
void operator()(float v)
{
if(auto res = self.invoke_effect(self.impl.effect, v, tick))
if(auto res = self.invoke_effect(0, 1, v, tick))
out.write_value(*res, 0);
}
void operator()(const std::string& v)
{
if(auto res = self.invoke_effect(self.impl.effect, std::stof(v), tick))
if(auto res = self.invoke_effect(0, 1, std::stof(v), tick))
out.write_value(*res, 0);
}
template <std::size_t N>
Expand Down Expand Up @@ -339,7 +351,7 @@ class safe_node<T> : public safe_node_base<T, safe_node<T>>
for(const ossia::timed_value& val : this->arg_value_ports.in->get_data())
{
this->arg_value_ports.out->write_value(
invoke_effect(this->impl.effect, val.value, tick), 0);
invoke_effect(0, 1, val.value, tick), 0);
}
}
else
Expand Down
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
Loading