MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
LogicProcessor.hpp
Go to the documentation of this file.
1#pragma once
2
5
6namespace MayaFlux::Buffers {
7
8/**
9 * @class LogicProcessor
10 * @brief Digital signal processor that applies boolean logic operations to data streams
11 *
12 * LogicProcessor bridges Nodes::Generator::Logic nodes with the buffer processing system,
13 * enabling sophisticated digital signal manipulation through various modulation strategies.
14 *
15 * The processor's job is simple:
16 * 1. Iterate through buffer samples
17 * 2. Generate logic values (0.0 or 1.0) by calling the Logic node
18 * 3. Apply logic to buffer data using a modulation strategy
19 *
20 * All logic computation (threshold detection, edge detection, state machines, etc.)
21 * is handled by the Logic node itself. The processor only manages iteration and
22 * application of results.
23 *
24 * Use cases include:
25 * - Binary pattern detection in data streams
26 * - Digital control signal generation
27 * - Conditional data flow routing
28 * - Event triggering based on signal characteristics
29 * - Digital state machine implementation
30 * - Signal quantization and discretization
31 */
32class MAYAFLUX_API LogicProcessor : public BufferProcessor {
33public:
34 /**
35 * @enum ModulationType
36 * @brief Defines how logic values modulate buffer content
37 *
38 * These are readymade strategies for applying binary logic (0.0/1.0) to
39 * continuous audio data, providing common compositional primitives for
40 * logic-based signal processing.
41 */
42 enum class ModulationType : uint8_t {
43 REPLACE, ///< Replace buffer with logic values: out = logic
44 MULTIPLY, ///< Gate/mask buffer: out = logic * buffer (standard audio gate)
45 ADD, ///< Offset buffer: out = logic + buffer
46
47 INVERT_ON_TRUE, ///< Invert signal when logic is true: out = logic ? -buffer : buffer
48 HOLD_ON_FALSE, ///< Hold last value when logic is false: out = logic ? buffer : last_value
49 ZERO_ON_FALSE, ///< Silence when logic is false: out = logic ? buffer : 0.0
50 CROSSFADE, ///< Smooth interpolation: out = lerp(0.0, buffer, logic)
51 THRESHOLD_REMAP, ///< Binary value selection: out = logic ? high_val : low_val
52 SAMPLE_AND_HOLD, ///< Sample on logic change: out = logic_changed ? buffer : held_value
53
54 CUSTOM ///< User-defined modulation function
55 };
56
57 /**
58 * @typedef ModulationFunction
59 * @brief Function type for custom digital signal transformations
60 *
61 * Defines a transformation that combines a logic value (0.0 or 1.0)
62 * with a buffer sample to produce a modulated output sample.
63 *
64 * Parameters:
65 * - double logic_val: The binary logic value (0.0 or 1.0)
66 * - double buffer_val: The original buffer sample value
67 *
68 * Returns:
69 * - double: The transformed output sample value
70 *
71 * This enables implementation of arbitrary digital transformations
72 * based on binary logic states, supporting complex conditional processing,
73 * digital filtering, and algorithmic decision trees in signal processing.
74 */
75 using ModulationFunction = std::function<double(double, double)>;
76
77 /**
78 * @brief Constructs a LogicProcessor with internal Logic node
79 * @param args Arguments to pass to the Logic constructor
80 *
81 * Creates a LogicProcessor that constructs its own Logic node internally.
82 */
83 template <typename... Args>
84 requires std::constructible_from<Nodes::Generator::Logic, Args...>
85 LogicProcessor(Args&&... args)
86 : m_logic(std::make_shared<Nodes::Generator::Logic>(std::forward<Args>(args)...))
87 , m_reset_between_buffers(false)
88 , m_use_internal(true)
89 , m_modulation_type(ModulationType::REPLACE)
90 , m_has_generated_data(false)
91 , m_high_value(1.0)
92 , m_low_value(0.0)
93 , m_last_held_value(0.0)
94 , m_last_logic_value(0.0)
95 {
96 }
97
98 /**
99 * @brief Constructs a LogicProcessor with external Logic node
100 * @param logic The logic node to use for processing
101 * @param reset_between_buffers Whether to reset logic state between buffer calls
102 *
103 * Creates a LogicProcessor that uses an external Logic node.
104 * NOTE: Using external Logic node implies side effects of any processing chain
105 * the node is connected to.
106 */
108 const std::shared_ptr<Nodes::Generator::Logic>& logic,
109 bool reset_between_buffers = false);
110
111 /**
112 * @brief Processes a buffer through the logic node
113 * @param buffer The audio buffer to process
114 *
115 * Processing steps:
116 * 1. Iterates through each sample in the buffer
117 * 2. Calls Logic node's process_sample() for each sample to get logic value
118 * 3. Applies the selected modulation strategy to combine logic with buffer data
119 *
120 * The Logic node handles all temporal state, callbacks, and logic computation.
121 * The processor only manages iteration and modulation application.
122 */
123 void processing_function(std::shared_ptr<Buffer> buffer) override;
124
125 /**
126 * @brief Called when the processor is attached to a buffer
127 * @param buffer The buffer this processor is being attached to
128 */
129 void on_attach(std::shared_ptr<Buffer> buffer) override;
130
131 /**
132 * @brief Called when the processor is detached from a buffer
133 * @param buffer The buffer this processor is being detached from
134 */
135 inline void on_detach(std::shared_ptr<Buffer>) override { }
136
137 /**
138 * @brief Generates discrete logic data from input without modifying any buffer
139 * @param num_samples Number of samples to generate
140 * @param input_data Input data to process through logic node
141 * @return Whether generation was successful
142 *
143 * This method allows for offline processing of data through the logic system,
144 * useful for analysis, preprocessing, or generating control signals independently
145 * of the main signal path.
146 */
147 bool generate(size_t num_samples, const std::vector<double>& input_data);
148
149 /**
150 * @brief Applies stored logic data to the given buffer
151 * @param buffer Buffer to apply logic data to
152 * @param modulation_func Optional function defining how to apply logic to audio
153 * @return Whether application was successful
154 *
155 * Use cases:
156 * - Conditional data transformation
157 * - Digital gating of signals
158 * - Binary masking operations
159 * - Custom digital signal processing chains
160 */
161 bool apply(const std::shared_ptr<Buffer>& buffer,
162 ModulationFunction modulation_func = nullptr);
163
164 /**
165 * @brief Gets the stored logic data
166 * @return Reference to the internal logic data vector
167 */
168 [[nodiscard]] const std::vector<double>& get_logic_data() const { return m_logic_data; }
169
170 /**
171 * @brief Checks if logic data has been generated
172 * @return True if logic data is available
173 */
174 [[nodiscard]] inline bool has_generated_data() const { return m_has_generated_data; }
175
176 /**
177 * @brief Set how logic values modulate buffer content
178 * @param type Modulation type to use
179 *
180 * Different modulation types enable various digital transformations:
181 * - REPLACE: Binary substitution of values
182 * - MULTIPLY: Binary masking/gating
183 * - ADD: Digital offset or bias
184 * - INVERT_ON_TRUE: Phase inversion based on logic state
185 * - HOLD_ON_FALSE: Sample-and-hold behavior
186 * - ZERO_ON_FALSE: Hard gating (silence on false)
187 * - CROSSFADE: Smooth amplitude interpolation
188 * - THRESHOLD_REMAP: Binary value mapping
189 * - SAMPLE_AND_HOLD: Update only on logic changes
190 * - CUSTOM: Arbitrary digital transformation
191 */
192 inline void set_modulation_type(ModulationType type) { m_modulation_type = type; }
193
194 /**
195 * @brief Get current modulation type
196 * @return Current modulation type
197 */
198 [[nodiscard]] inline ModulationType get_modulation_type() const { return m_modulation_type; }
199
200 /**
201 * @brief Set custom modulation function
202 *
203 * This sets the ModulationType to CUSTOM and uses the provided
204 * function for modulating the buffer. The function takes two
205 * parameters: the logic value and the buffer value, and returns
206 * the modulated result.
207 *
208 * Use cases:
209 * - Conditional data transformation based on logic state
210 * - Complex digital signal processing operations
211 * - Custom digital filtering based on binary conditions
212 * - Algorithmic decision trees in signal processing
213 *
214 * @param func Custom modulation function
215 */
216 void set_modulation_function(ModulationFunction func);
217
218 /**
219 * @brief Get current modulation function
220 * @return Current modulation function
221 */
222 [[nodiscard]] inline const ModulationFunction& get_modulation_function() const { return m_modulation_function; }
223
224 /**
225 * @brief Sets high and low values for THRESHOLD_REMAP mode
226 * @param high_val Value to use when logic is true (1.0)
227 * @param low_val Value to use when logic is false (0.0)
228 */
229 inline void set_threshold_remap_values(double high_val, double low_val)
230 {
231 m_high_value = high_val;
232 m_low_value = low_val;
233 }
234
235 /**
236 * @brief Gets the high value for THRESHOLD_REMAP mode
237 * @return High value
238 */
239 [[nodiscard]] inline double get_high_value() const { return m_high_value; }
240
241 /**
242 * @brief Gets the low value for THRESHOLD_REMAP mode
243 * @return Low value
244 */
245 [[nodiscard]] inline double get_low_value() const { return m_low_value; }
246
247 /**
248 * @brief Sets whether to reset logic state between buffer calls
249 * @param reset True to reset between buffers, false otherwise
250 *
251 * Controls whether the processor maintains state memory across buffer boundaries,
252 * enabling either stateless processing or continuous state tracking.
253 */
254 inline void set_reset_between_buffers(bool reset) { m_reset_between_buffers = reset; }
255
256 /**
257 * @brief Gets whether logic state is reset between buffer calls
258 * @return True if logic state is reset between buffers
259 */
260 [[nodiscard]] inline bool get_reset_between_buffers() const { return m_reset_between_buffers; }
261
262 /**
263 * @brief Checks if the processor is using the internal logic node
264 * @return True if using internal logic node, false otherwise
265 */
266 [[nodiscard]] inline bool is_using_internal() const { return m_use_internal; }
267
268 /**
269 * @brief Forces the processor to use a new internal logic node
270 *
271 * This replaces the current logic node with a new one constructed from the
272 * provided arguments, ensuring the processor uses its own internal logic
273 * instead of an external one.
274 */
275 template <typename... Args>
276 requires std::constructible_from<Nodes::Generator::Logic, Args...>
277 void force_use_internal(Args&&... args)
278 {
279 m_pending_logic = std::make_shared<Nodes::Generator::Logic>(std::forward<Args>(args)...);
280 }
281
282 /**
283 * @brief Updates the logic node used for processing
284 * @param logic New logic node to use
285 *
286 * NOTE: Using external Logic node implies side effects of any processing chain
287 * the node is connected to. This could mean that the buffer data is not used as
288 * input when the node's cached value is used.
289 */
290 inline void update_logic_node(const std::shared_ptr<Nodes::Generator::Logic>& logic)
291 {
292 m_pending_logic = logic;
293 }
294
295 /**
296 * @brief Gets the logic node used for processing
297 * @return Logic node used for processing
298 */
299 [[nodiscard]] inline std::shared_ptr<Nodes::Generator::Logic> get_logic() const { return m_logic; }
300
301private:
302 std::shared_ptr<Nodes::Generator::Logic> m_logic; ///< Logic node for processing
303 bool m_reset_between_buffers; ///< Whether to reset logic between buffers
304 bool m_use_internal; ///< Whether to use internal logic node
305 ModulationType m_modulation_type; ///< How logic values modulate buffer content
306 std::shared_ptr<Nodes::Generator::Logic> m_pending_logic; ///< Pending logic node update
307
308 ModulationFunction m_modulation_function; ///< Custom transformation function
309 std::vector<double> m_logic_data; ///< Stored logic processing results
310 bool m_has_generated_data; ///< Whether logic data has been generated
311
312 // State for special modulation modes
313 double m_high_value; ///< High value for THRESHOLD_REMAP
314 double m_low_value; ///< Low value for THRESHOLD_REMAP
315 double m_last_held_value; ///< Last held value for HOLD_ON_FALSE and SAMPLE_AND_HOLD
316 double m_last_logic_value; ///< Previous logic value for change detection
317};
318
319} // namespace MayaFlux::Buffers
Central computational transformation interface for continuous buffer processing.
void force_use_internal(Args &&... args)
Forces the processor to use a new internal logic node.
ModulationFunction m_modulation_function
Custom transformation function.
LogicProcessor(Args &&... args)
Constructs a LogicProcessor with internal Logic node.
const std::vector< double > & get_logic_data() const
Gets the stored logic data.
ModulationType
Defines how logic values modulate buffer content.
ModulationType get_modulation_type() const
Get current modulation type.
std::vector< double > m_logic_data
Stored logic processing results.
const ModulationFunction & get_modulation_function() const
Get current modulation function.
double get_high_value() const
Gets the high value for THRESHOLD_REMAP mode.
bool m_has_generated_data
Whether logic data has been generated.
void set_modulation_type(ModulationType type)
Set how logic values modulate buffer content.
double m_last_held_value
Last held value for HOLD_ON_FALSE and SAMPLE_AND_HOLD.
std::shared_ptr< Nodes::Generator::Logic > get_logic() const
Gets the logic node used for processing.
double m_high_value
High value for THRESHOLD_REMAP.
bool get_reset_between_buffers() const
Gets whether logic state is reset between buffer calls.
std::function< double(double, double)> ModulationFunction
Function type for custom digital signal transformations.
bool is_using_internal() const
Checks if the processor is using the internal logic node.
double m_low_value
Low value for THRESHOLD_REMAP.
std::shared_ptr< Nodes::Generator::Logic > m_logic
Logic node for processing.
bool has_generated_data() const
Checks if logic data has been generated.
double m_last_logic_value
Previous logic value for change detection.
ModulationType m_modulation_type
How logic values modulate buffer content.
void set_threshold_remap_values(double high_val, double low_val)
Sets high and low values for THRESHOLD_REMAP mode.
void set_reset_between_buffers(bool reset)
Sets whether to reset logic state between buffer calls.
std::shared_ptr< Nodes::Generator::Logic > m_pending_logic
Pending logic node update.
double get_low_value() const
Gets the low value for THRESHOLD_REMAP mode.
void on_detach(std::shared_ptr< Buffer >) override
Called when the processor is detached from a buffer.
bool m_use_internal
Whether to use internal logic node.
bool m_reset_between_buffers
Whether to reset logic between buffers.
void update_logic_node(const std::shared_ptr< Nodes::Generator::Logic > &logic)
Updates the logic node used for processing.
Digital signal processor that applies boolean logic operations to data streams.
Digital signal processor implementing boolean logic operations.
Definition Logic.hpp:162