MayaFlux 1.0.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_history(0)
10 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
11 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
12{
13 m_direct_function = create_polynomial_function(coefficients);
14 m_coef_direct = true;
15}
16
18 : m_mode(PolynomialMode::DIRECT)
19 , m_direct_function(std::move(function))
20 , m_scale_factor(1.F)
21 , m_history(0)
22 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
23 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
24{
25}
26
28 : m_mode(mode)
29 , m_buffer_function(std::move(function))
30 , m_buffer_size(buffer_size)
31 , m_history(buffer_size)
32 , m_linear_view(buffer_size, 0.0)
33 , m_scale_factor(1.F)
34 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
35 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
36{
37}
38
39Polynomial::Polynomial(CoefBufferFunction function, PolynomialMode mode, size_t buffer_size, std::vector<double> coefficients)
40 : m_mode(mode)
41 , m_coefficients(std::move(coefficients))
42 , m_history(buffer_size)
43 , m_linear_view(buffer_size, 0.0)
44 , m_buffer_size(buffer_size)
45 , m_scale_factor(1.F)
46 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
47 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
48{
49 m_coef_function = function;
50 m_buffer_function = bind_coefficients(std::move(function));
51 m_coef_bound = true;
52}
53
55{
56 double result = 0.0;
57
58 if (m_input_node) {
59 atomic_inc_modulator_count(m_input_node->m_modulator_count, 1);
60 uint32_t state = m_input_node->m_state.load();
61 if (state & NodeState::PROCESSED) {
62 input += m_input_node->get_last_output();
63 } else {
64 input = m_input_node->process_sample(input);
66 }
67 }
68
69 switch (m_mode) {
72 break;
73
75 if (m_buffer_size > 0) {
76 std::span<double> view;
77
80 } else {
83 }
84
85 result = m_buffer_function(view);
86
88 }
89 break;
90
92 if (m_buffer_size > 0) {
93 std::span<double> view;
94
97 } else {
100 }
101
102 result = m_buffer_function(view);
103 }
104 break;
105 }
106
107 result *= m_scale_factor;
108
109 m_last_output = result;
110
112 && !m_networked_node) {
113 notify_tick(result);
114 }
115
116 if (m_input_node) {
117 atomic_dec_modulator_count(m_input_node->m_modulator_count, 1);
119 }
120
121 return result;
122}
123
124std::vector<double> Polynomial::process_batch(unsigned int num_samples)
125{
126 std::vector<double> buffer(num_samples);
127
128 reset();
129
130 for (size_t i = 0; i < num_samples; ++i) {
131 buffer[i] = process_sample(0.0);
132 }
133
134 return buffer;
135}
136
138{
140 m_last_output = 0.0;
141}
142
143void Polynomial::set_coefficients(const std::vector<double>& coefficients)
144{
145 m_coefficients = coefficients;
146}
147
149{
150 m_direct_function = std::move(function);
152 m_coef_direct = false;
153}
154
156{
157 m_coef_bound = false;
158 m_coef_function = nullptr;
159 m_buffer_function = std::move(function);
160 m_mode = mode;
161
162 if (buffer_size != m_buffer_size) {
163 m_buffer_size = buffer_size;
164 m_history.resize(buffer_size);
165 m_linear_view.resize(buffer_size);
166 }
167}
168
170{
171 set_buffer_function(bind_coefficients(function), mode, buffer_size);
172 m_coef_function = std::move(function);
173 m_coef_bound = true;
174}
175
177{
178 return [this, function = std::move(function)](std::span<double> window) {
179 return function(window, std::span<double>(m_coefficients));
180 };
181}
182
183std::shared_ptr<Polynomial> Polynomial::clone() const
184{
185 std::shared_ptr<Polynomial> copy;
186
187 if (m_coef_bound) {
188 copy = std::make_shared<Polynomial>(m_coef_function, m_mode, m_buffer_size, m_coefficients);
189 } else if (m_mode == PolynomialMode::DIRECT) {
190 copy = m_coef_direct
191 ? std::make_shared<Polynomial>(m_coefficients)
192 : std::make_shared<Polynomial>(m_direct_function);
193 } else {
194 copy = std::make_shared<Polynomial>(m_buffer_function, m_mode, m_buffer_size);
195 }
196
197 copy->m_coefficients = m_coefficients;
198 copy->m_scale_factor = m_scale_factor;
199 copy->m_input_node = m_input_node;
200 return copy;
201}
202
203void Polynomial::set_initial_conditions(const std::vector<double>& initial_values)
204{
205 m_history.set_initial_conditions(initial_values);
206}
207
209{
210 size_t lookback = std::min(m_current_buffer_position, m_buffer_size - 1);
211 size_t view_size = std::min(lookback + 1, m_buffer_size);
212
213 m_linear_view[0] = input;
214
215 for (size_t i = 1; i < view_size && i <= lookback; ++i) {
217 }
218
220 return { m_linear_view.data(), view_size };
221}
222
224{
225 return [coefficients](double x) {
226 return power_sum(coefficients, x);
227 };
228}
229
230double Polynomial::power_sum(const std::vector<double>& coefficients, double x) noexcept
231{
232 double result = 0.0;
233 double x_power = 1.0;
234
235 for (double coefficient : std::ranges::reverse_view(coefficients)) {
236 result += coefficient * x_power;
237 x_power *= x;
238 }
239
240 return result;
241}
242
244{
245 auto view = m_history.linearized_view();
246
247 if (m_gpu_compatible) {
253
254 m_context_gpu.gpu_float_buffer.resize(view.size());
255 for (size_t i = 0; i < view.size(); ++i)
256 m_context_gpu.gpu_float_buffer[i] = static_cast<float>(view[i]);
257
258 m_context_gpu.m_gpu_data = std::span<const float>(m_context_gpu.gpu_float_buffer);
259 } else {
265 }
266}
267
269{
270 if (m_gpu_compatible) {
271 return m_context_gpu;
272 }
273 return m_context;
274}
275
289
303
304std::vector<std::pair<ModulatorRole, std::shared_ptr<Node>>>
306{
307 if (m_input_node)
309 return {};
310}
311
312} // namespace MayaFlux::Nodes::Generator
Core::GlobalInputConfig input
Definition Config.cpp:42
std::shared_ptr< NetworkGeometryBuffer > buffer
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
uint32_t mode
glm::vec3 value
void resize(size_t new_capacity)
Resize buffer capacity.
void restore_state(const std::vector< T > &state)
Restore previously saved state.
std::span< T > linearized_view()
Get mutable linearized view of entire history.
void overwrite_newest(const T &value)
Overwrite the newest element without advancing position.
void push(const T &value)
Push new value to front of history.
void reset()
Reset buffer to initial state (all zeros)
std::vector< T > save_state() const
Save current state for later restoration.
void set_initial_conditions(const std::vector< T > &values)
Set initial conditions.
void notify_tick(double value) override
Notifies all registered callbacks with the current context.
Definition Generator.cpp:56
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.
BufferFunction bind_coefficients(CoefBufferFunction function)
Converts coefficient vector to a polynomial function.
CoefBufferFunction m_coef_function
The function behind m_buffer_function while a CoefBufferFunction is bound.
std::function< double(std::span< double >)> BufferFunction
Function type for recursive/feedforward polynomial evaluation.
std::vector< double > m_saved_coefficients
Saved coefficient array, used when a CoefBufferFunction is bound.
PolynomialMode m_mode
Current processing mode.
std::shared_ptr< Polynomial > clone() const
An independent node with the same behaviour and fresh history.
std::function< double(std::span< double >, std::span< double >)> CoefBufferFunction
Function type for recursive/feedforward evaluation with access to the coefficient array.
DirectFunction create_polynomial_function(const std::vector< double > &coefficients)
Creates a polynomial function from coefficients.
static double power_sum(const std::vector< double > &coefficients, double x) noexcept
Evaluates the coefficient list at x, highest power first.
std::vector< std::pair< ModulatorRole, std::shared_ptr< Node > > > get_modulators() const override
Retrieves the current modulators connected to this node.
std::vector< double > m_saved_history_state
Saved state of the history buffer.
Memory::HistoryBuffer< double > m_history
Ring buffer for input/output history.
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 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
View into external buffer.
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.
std::vector< double > m_linear_view
Linearized view of history for easy access.
BufferFunction m_buffer_function
Function for recursive/feedforward mode.
bool m_coef_direct
True while DIRECT output is evaluated from m_coefficients.
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.
bool m_coef_bound
True once a CoefBufferFunction has been bound.
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.
std::span< const float > m_gpu_data
double value
Current sample value.
Definition Node.hpp:63
Base context class for node callbacks.
Definition Node.hpp:53
bool m_state_saved
tracks if the node's state has been saved by a snapshot operation
Definition Node.hpp:498
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:493
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:441
bool m_fire_events_during_snapshot
Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don...
Definition Node.hpp:528
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:450
@ 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], ...)
@ PROCESSED
Node has been processed this cycle.
Definition NodeSpec.hpp:49
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.
void atomic_add_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically adds a flag to a node state.