9 const std::shared_ptr<Nodes::Generator::Logic>& logic,
10 bool reset_between_buffers)
12 , m_reset_between_buffers(reset_between_buffers)
13 , m_use_internal(false)
15 , m_has_generated_data(false)
18 , m_last_held_value(0.0)
19 , m_last_logic_value(0.0)
25 if (!
m_logic || input_data.empty()) {
55 }
else if (!
m_keys.empty() && parallel) {
71 const size_t available = input_data.size();
72 for (
size_t i = 0; i < num_samples; ++i) {
80 for (
const auto& key :
m_keys) {
89 const size_t available = input_data.size();
92 for (
size_t i = 0; i < num_samples; ++i) {
95 m_slots[k] = (key && i < key->get_data().size()) ? key->get_data()[i] : 0.0;
104 const uint32_t bits = std::clamp(
m_plane_bits, uint32_t { 1 }, uint32_t { 24 });
108 for (uint32_t plane = 0; plane < bits; ++plane) {
117 const size_t key_count = parallel ?
m_live_keys.size() : 0;
119 m_slots.assign(key_count + 1, 0.0);
121 const size_t available = input_data.size();
124 for (
size_t i = 0; i < num_samples; ++i) {
126 for (
size_t k = 0; k < key_count; ++k) {
128 m_key_words[k] = (key && i < key->get_data().size())
134 for (uint32_t plane = 0; plane < bits; ++plane) {
135 const auto bit_of = [plane](uint32_t w) {
return static_cast<double>((w >> plane) & 1U); };
139 for (
size_t k = 0; k < key_count; ++k) {
147 word |= (
out > 0.5 ? 1U : 0U) << plane;
156 if (num_samples == 0) {
160 const size_t available = input_data.size();
162 const auto count =
static_cast<std::ptrdiff_t
>(num_samples);
164 m_cells.assign(num_samples, 0);
168 for (
size_t i = 0; i < num_samples; ++i) {
169 uint8_t cell = (i < available && input_data[i] > 0.0) ? 1 : 0;
176 for (
size_t generation = 0; generation <
m_generations; ++generation) {
177 for (std::ptrdiff_t i = 0; i <
count; ++i) {
178 for (
size_t k = 0; k <
width; ++k) {
179 std::ptrdiff_t at = i +
static_cast<std::ptrdiff_t
>(
m_radius) -
static_cast<std::ptrdiff_t
>(k);
181 if (at >= 0 && at <
count) {
182 cell =
m_cells[
static_cast<size_t>(at)];
185 cell =
m_cells[
static_cast<size_t>(at)];
194 for (
size_t i = 0; i < num_samples; ++i) {
216 m_plane_bits = bits == 0 ? 0 : std::clamp(bits, uint32_t { 1 }, uint32_t { 24 });
242 auto& buffer_data = std::dynamic_pointer_cast<AudioBuffer>(
buffer)->get_data();
243 size_t min_size = std::min(
m_logic_data.size(), buffer_data.size());
245 if (!modulation_func) {
248 modulation_func = [](
double logic_val,
double ) {
254 modulation_func = [](
double logic_val,
double buffer_val) {
255 return logic_val * buffer_val;
260 modulation_func = [](
double logic_val,
double buffer_val) {
261 return logic_val + buffer_val;
266 modulation_func = [](
double logic_val,
double buffer_val) {
267 return logic_val > 0.5 ? -buffer_val : buffer_val;
276 modulation_func = [
this](
double logic_val,
double buffer_val)
mutable {
277 if (logic_val > 0.5) {
286 modulation_func = [](
double logic_val,
double buffer_val) {
287 return logic_val > 0.5 ? buffer_val : 0.0;
292 modulation_func = [](
double logic_val,
double buffer_val) {
293 return buffer_val * logic_val;
298 modulation_func = [
this](
double logic_val,
double ) {
309 modulation_func = [
this, first_sample =
true](
double logic_val,
double buffer_val)
mutable {
311 first_sample =
false;
330 modulation_func = [](
double logic_val,
double ) {
336 for (
size_t i = 0; i < min_size; ++i) {
337 buffer_data[i] = modulation_func(
m_logic_data[i], buffer_data[i]);
349 auto audio_buffer = std::dynamic_pointer_cast<AudioBuffer>(
buffer);
350 if (!audio_buffer || audio_buffer->get_data().empty()) {
354 generate(audio_buffer->get_num_samples(), audio_buffer->get_data());
380 copy->m_use_internal =
true;
std::shared_ptr< NetworkGeometryBuffer > buffer
std::vector< float > * out
Samples read as fixed width binary words.
std::vector< double > m_slots
Input slots handed to the node.
void on_attach(const std::shared_ptr< Buffer > &buffer) override
Called when the processor is attached to a buffer.
ModulationFunction m_modulation_function
Custom transformation function.
std::vector< std::shared_ptr< Nodes::Generator::Logic > > m_plane_nodes
One clone of the node per bit plane.
LogicProcessor(Args &&... args)
Constructs a LogicProcessor with internal Logic node.
size_t m_generations
Automaton steps per block, 0 when off.
ModulationType
Defines how logic values modulate buffer content.
@ MULTIPLY
Gate/mask buffer: out = logic * buffer (standard audio gate)
@ SAMPLE_AND_HOLD
Sample on logic change: out = logic_changed ? buffer : held_value.
@ REPLACE
Replace buffer with logic values: out = logic.
@ CUSTOM
User-defined modulation function.
@ ZERO_ON_FALSE
Silence when logic is false: out = logic ? buffer : 0.0.
@ INVERT_ON_TRUE
Invert signal when logic is true: out = logic ? -buffer : buffer.
@ ADD
Offset buffer: out = logic + buffer.
@ CROSSFADE
Smooth interpolation: out = lerp(0.0, buffer, logic)
@ HOLD_ON_FALSE
Hold last value when logic is false: out = logic ? buffer : last_value.
@ THRESHOLD_REMAP
Binary value selection: out = logic ? high_val : low_val.
std::vector< double > m_logic_data
Stored logic processing results.
bool m_wrap
Whether the automaton's block ends meet.
std::vector< uint8_t > m_next_cells
Automaton cells of the next generation.
bool m_has_generated_data
Whether logic data has been generated.
std::vector< uint32_t > m_key_words
Words of the keys at the current sample.
double m_last_held_value
Last held value for HOLD_ON_FALSE and SAMPLE_AND_HOLD.
void generate_temporal(size_t num_samples, const std::vector< double > &input_data)
void set_neighbourhood(size_t radius, size_t generations=1, bool wrap=true, bool memory=false)
Treats the samples of a block as cells of an automaton.
std::vector< uint8_t > m_previous_cells
Last automaton result, kept when memory is on.
double m_high_value
High value for THRESHOLD_REMAP.
std::function< double(double, double)> ModulationFunction
Function type for custom digital signal transformations.
std::vector< uint8_t > m_cells
Automaton cells.
bool generate(size_t num_samples, const std::vector< double > &input_data)
Generates discrete logic data from input without modifying any buffer.
size_t m_radius
Neighbourhood radius of the automaton.
uint32_t m_plane_bits
Word width when processing bit planes, 0 when off.
double m_low_value
Low value for THRESHOLD_REMAP.
std::shared_ptr< Nodes::Generator::Logic > m_logic
Logic node for processing.
std::shared_ptr< Nodes::Generator::Logic > m_plane_template
The node the plane clones were taken from.
void generate_planes(size_t num_samples, const std::vector< double > &input_data)
void generate_keyed(size_t num_samples, const std::vector< double > &input_data)
double m_last_logic_value
Previous logic value for change detection.
void set_bit_planes(uint32_t bits)
Processes every sample as a word of bit streams, one node per bit.
ModulationType m_modulation_type
How logic values modulate buffer content.
void set_modulation_function(ModulationFunction func)
Set custom modulation function.
bool m_memory
Whether blocks perturb the previous automaton result.
void clear_keys()
Removes every key.
std::vector< std::weak_ptr< AudioBuffer > > m_keys
Buffers read as extra input slots.
std::shared_ptr< LogicProcessor > clone() const
An independent processor over a clone of the node.
std::shared_ptr< Nodes::Generator::Logic > m_pending_logic
Pending logic node update.
std::vector< std::shared_ptr< AudioBuffer > > m_live_keys
Keys locked for the current block.
void clear_neighbourhood()
Turns the automaton off.
bool m_use_internal
Whether to use internal logic node.
void add_key(const std::shared_ptr< AudioBuffer > &buffer)
Reads another buffer as an extra input slot of a parallel node.
void processing_function(const std::shared_ptr< Buffer > &buffer) override
Processes a buffer through the logic node.
bool apply(const std::shared_ptr< Buffer > &buffer, ModulationFunction modulation_func=nullptr)
Applies stored logic data to the given buffer.
bool m_reset_between_buffers
Whether to reset logic between buffers.
void generate_spatial(size_t num_samples, const std::vector< double > &input_data)
double from_word(uint32_t word, uint32_t bits) noexcept
The value of an offset binary word; bits above the width are ignored.
uint32_t to_word(double value, uint32_t bits) noexcept
The offset binary word of a value, clamped to [-1, 1].
@ MULTI_INPUT
Parallel evaluation of multiple input signals.
@ INACTIVE
Engine is not processing this node.