MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Polynomial.cpp
Go to the documentation of this file.
1#include "Polynomial.hpp"
2
4
5Polynomial::Polynomial(const std::vector<double>& coefficients)
6 : m_mode(PolynomialMode::DIRECT)
7 , m_coefficients(coefficients)
8 , m_scale_factor(1.F)
9 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
10 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
11{
12 m_direct_function = create_polynomial_function(coefficients);
13}
14
16 : m_mode(PolynomialMode::DIRECT)
17 , m_direct_function(std::move(function))
18 , m_scale_factor(1.F)
19 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
20 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
21{
22}
23
24Polynomial::Polynomial(BufferFunction function, PolynomialMode mode, size_t buffer_size)
25 : m_mode(mode)
26 , m_buffer_function(std::move(function))
27 , m_ring_count(buffer_size)
28 , m_buffer_size(buffer_size)
29 , m_ring_data(buffer_size, 0.0)
30 , m_linear_view(buffer_size, 0.0)
31 , m_scale_factor(1.F)
32 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
33 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
34{
35}
36
37double Polynomial::process_sample(double input)
38{
39 double result = 0.0;
40
41 if (m_input_node) {
42 atomic_inc_modulator_count(m_input_node->m_modulator_count, 1);
43 uint32_t state = m_input_node->m_state.load();
44 if (state & Utils::NodeState::PROCESSED) {
45 input += m_input_node->get_last_output();
46 } else {
47 input = m_input_node->process_sample(input);
49 }
50 }
51
52 switch (m_mode) {
54 result = m_direct_function(input);
55 break;
56
58 if (m_buffer_size > 0) {
59 std::span<double> view;
60
62 view = external_context_view(input);
63 } else {
64 ring_push(input);
65 view = linearized_view();
66 }
67
68 result = m_buffer_function(view);
69
70 m_ring_data[m_ring_head] = result;
71 }
72 break;
73
75 if (m_buffer_size > 0) {
76 std::span<double> view;
77
79 view = external_context_view(input);
80 } else {
81 ring_push(input);
82 view = linearized_view();
83 }
84
85 result = m_buffer_function(view);
86 }
87 break;
88 }
89
90 result *= m_scale_factor;
91
92 m_last_output = result;
93
95 && !m_networked_node) {
96 notify_tick(result);
97 }
98
99 if (m_input_node) {
100 atomic_dec_modulator_count(m_input_node->m_modulator_count, 1);
102 }
103
104 return result;
105}
106
107std::vector<double> Polynomial::process_batch(unsigned int num_samples)
108{
109 std::vector<double> buffer(num_samples);
110
111 reset();
112
113 for (size_t i = 0; i < num_samples; ++i) {
114 buffer[i] = process_sample(0.0);
115 }
116
117 return buffer;
118}
119
121{
122 std::ranges::fill(m_ring_data, 0.0);
123 m_ring_head = 0;
125 m_last_output = 0.0;
126}
127
128void Polynomial::set_coefficients(const std::vector<double>& coefficients)
129{
130 m_coefficients = coefficients;
131}
132
134{
135 m_direct_function = std::move(function);
137}
138
139void Polynomial::set_buffer_function(BufferFunction function, PolynomialMode mode, size_t buffer_size)
140{
141 m_buffer_function = std::move(function);
142 m_mode = mode;
143
144 if (buffer_size != m_buffer_size) {
145 m_buffer_size = buffer_size;
146 m_ring_data.resize(buffer_size, 0.0);
147 m_linear_view.resize(buffer_size, 0.0);
148 m_ring_head = 0;
149 m_ring_count = 0;
150 }
151}
152
153void Polynomial::set_initial_conditions(const std::vector<double>& initial_values)
154{
155 std::ranges::fill(m_ring_data, 0.0);
156
157 size_t count = std::min(initial_values.size(), m_buffer_size);
158 for (size_t i = 0; i < count; ++i) {
159 m_ring_data[i] = initial_values[i];
160 }
161
162 m_ring_head = 0;
164}
165
166void Polynomial::ring_push(double val)
167{
168 if (m_buffer_size == 0)
169 return;
173 ++m_ring_count;
174}
175
177{
178 for (size_t i = 0; i < m_ring_count; ++i) {
180 }
181 return { m_linear_view.data(), m_ring_count };
182}
183
184std::span<double> Polynomial::external_context_view(double input)
185{
186 size_t lookback = std::min(m_current_buffer_position, m_buffer_size - 1);
187 size_t view_size = std::min(lookback + 1, m_buffer_size);
188
189 m_linear_view[0] = input;
190
191 for (size_t i = 1; i < view_size && i <= lookback; ++i) {
193 }
194
196 return { m_linear_view.data(), view_size };
197}
198
200{
201 return [coefficients](double x) {
202 double result = 0.0;
203 double x_power = 1.0;
204
205 for (double coefficient : std::ranges::reverse_view(coefficients)) {
206 result += coefficient * x_power;
207 x_power *= x;
208 }
209
210 return result;
211 };
212}
213
215{
216 auto view = linearized_view();
217
218 if (m_gpu_compatible) {
219 m_context_gpu.value = value;
224 } else {
225 m_context.value = value;
230 }
231}
232
233void Polynomial::notify_tick(double value)
234{
235 update_context(value);
236 auto& ctx = get_last_context();
237
238 for (auto& callback : m_callbacks) {
239 callback(ctx);
240 }
241 for (auto& [callback, condition] : m_conditional_callbacks) {
242 if (condition(ctx)) {
243 callback(ctx);
244 }
245 }
246}
247
249{
250 if (m_gpu_compatible) {
251 return m_context_gpu;
252 }
253 return m_context;
254}
255
268
281
282} // namespace MayaFlux::Nodes::Generator
std::span< double > m_output_buffer
Copy of output buffer.
PolynomialMode m_mode
Current processing mode.
std::span< double > m_input_buffer
Copy of input buffer.
std::function< double(std::span< double >)> BufferFunction
Function type for recursive/feedforward polynomial evaluation.
PolynomialMode m_mode
Converts coefficient vector to a polynomial function.
DirectFunction create_polynomial_function(const std::vector< double > &coefficients)
Creates a polynomial function from coefficients.
void update_context(double value) override
Updates the context object with the current node state.
void set_direct_function(DirectFunction function)
Sets a custom direct function.
void set_initial_conditions(const std::vector< double > &initial_values)
Sets initial conditions for recursive mode.
double process_sample(double input=0.) override
Processes a single sample.
void notify_tick(double value) override
Notifies all registered callbacks about a new sample.
std::vector< double > m_saved_ring_data
void set_buffer_function(BufferFunction function, PolynomialMode mode, size_t buffer_size)
Sets a custom buffer function.
double m_scale_factor
Scaling factor for output.
Polynomial(const std::vector< double > &coefficients)
Constructs a Polynomial generator in direct mode with coefficient-based definition.
Definition Polynomial.cpp:5
std::span< double > m_external_buffer_context
std::span< double > external_context_view(double input)
size_t m_buffer_size
Maximum size of the buffers.
void set_coefficients(const std::vector< double > &coefficients)
Sets the polynomial coefficients (for direct mode)
void reset()
Resets the generator to its initial state.
BufferFunction m_buffer_function
Function for recursive/feedforward mode.
void restore_state() override
Restores the node's state from the last save Recursively cascades through all connected modulator nod...
std::shared_ptr< Node > m_input_node
Input node for processing.
std::function< double(double)> DirectFunction
Function type for direct polynomial evaluation.
NodeContext & get_last_context() override
Retrieves the last created context object.
DirectFunction m_direct_function
Function for direct mode.
void save_state() override
Saves the node's current state for later restoration Recursively cascades through all connected modul...
std::vector< double > m_coefficients
Polynomial coefficients (if using coefficient-based definition)
std::vector< double > process_batch(unsigned int num_samples) override
Processes multiple samples at once.
double value
Current sample value.
Definition Node.hpp:40
Base context class for node callbacks.
Definition Node.hpp:30
std::vector< NodeHook > m_callbacks
Collection of standard callback functions.
Definition Node.hpp:403
bool m_state_saved
tracks if the node's state has been saved by a snapshot operation
Definition Node.hpp:426
bool m_networked_node
Flag indicating if the node is part of a NodeNetwork This flag is used to disable event firing when t...
Definition Node.hpp:421
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:374
bool m_fire_events_during_snapshot
Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don...
Definition Node.hpp:448
std::vector< std::pair< NodeHook, NodeCondition > > m_conditional_callbacks
Collection of conditional callback functions with their predicates.
Definition Node.hpp:413
bool m_gpu_compatible
Flag indicating if the node supports GPU processing This flag is set by derived classes to indicate w...
Definition Node.hpp:383
@ DIRECT
Stateless evaluation of current input only (combinational logic)
PolynomialMode
Defines how the polynomial function processes input values.
@ RECURSIVE
Evaluates using current and previous outputs: y[n] = f(y[n-1], y[n-2], ...)
@ DIRECT
Evaluates f(x) where x is the current phase/input.
@ FEEDFORWARD
Evaluates using current and previous inputs: y[n] = f(x[n], x[n-1], ...)
void atomic_add_flag(std::atomic< Utils::NodeState > &state, Utils::NodeState flag)
Atomically adds a flag to a node state.
Definition NodeUtils.cpp:96
void try_reset_processed_state(std::shared_ptr< Node > node)
Attempts to reset the processed state of a node.
void atomic_inc_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically increments the modulator count by a specified amount.
void atomic_dec_modulator_count(std::atomic< uint32_t > &count, int amount)
Atomically decrements the modulator count by a specified amount.
@ PROCESSED
Node has been processed this cycle.
Definition Utils.hpp:34