Skip to content
Draft
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
16 changes: 8 additions & 8 deletions include/avnd/binding/ossia/controls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <avnd/introspection/input.hpp>
#include <avnd/introspection/output.hpp>
// #include <boost/smart_ptr/atomic_shared_ptr.hpp>
#include <ossia/detail/lockfree_queue.hpp>
#include <ossia/detail/triple_buffer.hpp>

#include <atomic>
#include <bitset>
Expand Down Expand Up @@ -77,7 +77,8 @@ struct controls_input_queue<T>
using i_tuple
= avnd::filter_and_apply<controls_type_t, avnd::control_input_introspection, T>;

ossia::mpmc_queue<i_tuple> ins_queue;
//! The latest control values, for the UI.
ossia::triple_buffer<i_tuple> ins_buffer;
std::bitset<i_size> inputs_set;
//! Bool controls pressed by an impulse in this tick: released once the
//! tick is processed (see momentary_bool_port).
Expand All @@ -92,21 +93,20 @@ struct controls_output_queue<T>
using o_tuple
= avnd::filter_and_apply<controls_type_t, avnd::control_output_introspection, T>;

ossia::mpmc_queue<o_tuple> outs_queue;
//! The latest control output values, for the UI.
ossia::triple_buffer<o_tuple> outs_buffer;

std::bitset<o_size> outputs_set;

//! Whether anything is draining outs_queue. The host clears it when it
//! installs no reader: enqueuing then grows the queue without bound and
//! allocates inside the audio callback for a value nobody reads.
std::atomic_bool notify_ui{true};
};

template <typename T>
struct controls_queue
: controls_input_queue<T>
, controls_output_queue<T>
{
//! Whether the host reads the values above. When it does not, the node
//! does not copy them.
std::atomic_bool notify_ui{true};
};

}
35 changes: 24 additions & 11 deletions include/avnd/binding/ossia/node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,26 +586,38 @@ class safe_node_base : public safe_node_base_base<T>

void process_smooth() { this->smooth.smooth_all(this->impl); }

typename controls_input_queue<T>::i_tuple make_controls_in_tuple()
// Copies the control values field by field into a buffer that was written
// before, so that the values that hold memory reuse it.
void publish_controls_in()
{
auto& buf = this->control.ins_buffer.write_buffer();
// We only care about the inputs of the first one, since they're all the same
for(auto state : this->impl.full_state())
{
return avnd::control_input_introspection<T>::filter_tuple(
state.inputs, [](auto& field) { return field.value; });
avnd::control_input_introspection<T>::for_all_n(
state.inputs, [&]<std::size_t N>(auto& field, avnd::predicate_index<N>) {
using namespace std;
get<N>(buf) = field.value;
});
this->control.ins_buffer.publish();
break;
}
return {};
}

typename controls_output_queue<T>::o_tuple make_controls_out_tuple()
void publish_controls_out()
{
auto& buf = this->control.outs_buffer.write_buffer();
// Note that this does not yet make a lot of sens for polyphonic effects
for(auto state : this->impl.full_state())
{
return avnd::control_output_introspection<T>::filter_tuple(
state.outputs, [](auto& field) { return field.value; });
avnd::control_output_introspection<T>::for_all_n(
state.outputs, [&]<std::size_t N>(auto& field, avnd::predicate_index<N>) {
using namespace std;
get<N>(buf) = field.value;
});
this->control.outs_buffer.publish();
break;
}
return {};
}

void finish_run()
Expand All @@ -630,8 +642,9 @@ class safe_node_base : public safe_node_base_base<T>
{
if(this->control.inputs_set.any())
{
// Notify the UI
this->control.ins_queue.enqueue(make_controls_in_tuple());
// Notify the UI, unless nothing is listening
if(this->control.notify_ui.load(std::memory_order_relaxed))
publish_controls_in();
this->control.inputs_set.reset();
}
}
Expand All @@ -651,7 +664,7 @@ class safe_node_base : public safe_node_base_base<T>
{
// Notify the UI, unless nothing is listening
if(this->control.notify_ui.load(std::memory_order_relaxed))
this->control.outs_queue.enqueue(make_controls_out_tuple());
publish_controls_out();
this->control.outputs_set.reset();
}
}
Expand Down