MayaFlux 0.3.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}
15
17 : m_mode(PolynomialMode::DIRECT)
18 , m_direct_function(std::move(function))
19 , m_scale_factor(1.F)
20 , m_history(0)
21 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
22 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
23{
24}
25
26Polynomial::Polynomial(BufferFunction function, PolynomialMode mode, size_t buffer_size)
27 : m_mode(mode)
28 , m_buffer_function(std::move(function))
29 , m_buffer_size(buffer_size)
30 , m_history(buffer_size)
31 , m_linear_view(buffer_size, 0.0)
32 , m_scale_factor(1.F)
33 , m_context(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients)
34 , m_context_gpu(0.0, m_mode, m_buffer_size, {}, {}, m_coefficients, get_gpu_data_buffer())
35{
36}
37
38double Polynomial::process_sample(double input)
39{
40 double result = 0.0;
41
42 if (m_input_node) {
43 atomic_inc_modulator_count(m_input_node->m_modulator_count, 1);
44 uint32_t state = m_input_node->m_state.load();
45 if (state & NodeState::PROCESSED) {
46 input += m_input_node->get_last_output();
47 } else {
48 input = m_input_node->process_sample(input);
50 }
51 }
52
53 switch (m_mode) {
55 result = m_direct_function(input);
56 break;
57
59 if (m_buffer_size > 0) {
60 std::span<double> view;
61
63 view = external_context_view(input);
64 } else {
65 m_history.push(input);
67 }
68
69 result = m_buffer_function(view);
70
72 }
73 break;
74
76 if (m_buffer_size > 0) {
77 std::span<double> view;
78
80 view = external_context_view(input);
81 } else {
82 m_history.push(input);
84 }
85
86 result = m_buffer_function(view);
87 }
88 break;
89 }
90
91 result *= m_scale_factor;
92
93 m_last_output = result;
94
96 && !m_networked_node) {
97 notify_tick(result);
98 }
99
100 if (m_input_node) {
101 atomic_dec_modulator_count(m_input_node->m_modulator_count, 1);
103 }
104
105 return result;
106}
107
108std::vector<double> Polynomial::process_batch(unsigned int num_samples)
109{
110 std::vector<double> buffer(num_samples);
111
112 reset();
113
114 for (size_t i = 0; i < num_samples; ++i) {
115 buffer[i] = process_sample(0.0);
116 }
117
118 return buffer;
119}
120
122{
124 m_last_output = 0.0;
125}
126
127void Polynomial::set_coefficients(const std::vector<double>& coefficients)
128{
129 m_coefficients = coefficients;
130}
131
133{
134 m_direct_function = std::move(function);
136}
137
138void Polynomial::set_buffer_function(BufferFunction function, PolynomialMode mode, size_t buffer_size)
139{
140 m_buffer_function = std::move(function);
141 m_mode = mode;
142
143 if (buffer_size != m_buffer_size) {
144 m_buffer_size = buffer_size;
145 m_history.resize(buffer_size);
146 m_linear_view.resize(buffer_size);
147 }
148}
149
150void Polynomial::set_initial_conditions(const std::vector<double>& initial_values)
151{
152 m_history.set_initial_conditions(initial_values);
153}
154
155std::span<double> Polynomial::external_context_view(double input)
156{
157 size_t lookback = std::min(m_current_buffer_position, m_buffer_size - 1);
158 size_t view_size = std::min(lookback + 1, m_buffer_size);
159
160 m_linear_view[0] = input;
161
162 for (size_t i = 1; i < view_size && i <= lookback; ++i) {
164 }
165
167 return { m_linear_view.data(), view_size };
168}
169
171{
172 return [coefficients](double x) {
173 double result = 0.0;
174 double x_power = 1.0;
175
176 for (double coefficient : std::ranges::reverse_view(coefficients)) {
177 result += coefficient * x_power;
178 x_power *= x;
179 }
180
181 return result;
182 };
183}
184
186{
187 auto view = m_history.linearized_view();
188
189 if (m_gpu_compatible) {
190 m_context_gpu.value = value;
195
196 m_context_gpu.gpu_float_buffer.resize(view.size());
197 for (size_t i = 0; i < view.size(); ++i)
198 m_context_gpu.gpu_float_buffer[i] = static_cast<float>(view[i]);
199
200 m_context_gpu.m_gpu_data = std::span<const float>(m_context_gpu.gpu_float_buffer);
201 } else {
202 m_context.value = value;
207 }
208}
209
210void Polynomial::notify_tick(double value)
211{
212 update_context(value);
213 auto& ctx = get_last_context();
214
215 for (auto& callback : m_callbacks) {
216 callback(ctx);
217 }
218 for (auto& [callback, condition] : m_conditional_callbacks) {
219 if (condition(ctx)) {
220 callback(ctx);
221 }
222 }
223}
224
226{
227 if (m_gpu_compatible) {
228 return m_context_gpu;
229 }
230 return m_context;
231}
232
234{
237
238 if (m_input_node)
239 m_input_node->save_state();
240
241 m_state_saved = true;
242}
243
254
255} // namespace MayaFlux::Nodes::Generator
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.
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.
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 notify_tick(double value) override
Notifies all registered callbacks about a new 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.
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.
std::span< const float > m_gpu_data
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:406
bool m_state_saved
tracks if the node's state has been saved by a snapshot operation
Definition Node.hpp:429
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:424
double m_last_output
The most recent sample value generated by this oscillator.
Definition Node.hpp:377
bool m_fire_events_during_snapshot
Internal flag controlling whether notify_tick fires during state snapshots Default: false (events don...
Definition Node.hpp:455
std::vector< std::pair< NodeHook, NodeCondition > > m_conditional_callbacks
Collection of conditional callback functions with their predicates.
Definition Node.hpp:416
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:386
@ 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 atomic_add_flag(std::atomic< NodeState > &state, NodeState flag)
Atomically adds a flag to a node state.
Definition NodeUtils.cpp:94
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.