MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Timers.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Tasks.hpp"
4
5namespace MayaFlux::Nodes {
6class Node;
7class NodeGraphManager;
8}
9
10namespace MayaFlux::Kriya {
11
12/**
13 * @class Timer
14 * @brief High-level utility for scheduling one-shot timed callbacks
15 *
16 * The Timer class provides a convenient way to schedule a function to execute
17 * after a specified delay. It wraps the lower-level computational routine system in a
18 * simple interface that's easier to use for common timing scenarios.
19 *
20 * Unlike traditional timers which can drift due to system load, Timer uses
21 * the engine's sample-accurate clock to ensure precise, deterministic timing
22 * that's perfectly synchronized with the processing pipeline.
23 *
24 * Example usage:
25 * ```cpp
26 * // Create a timer
27 * Timer timer(*scheduler);
28 *
29 * // Schedule a callback to execute after 2 seconds
30 * timer.schedule(2.0, []() {
31 * std::cout << "Two seconds have passed!" << std::endl;
32 * });
33 * ```
34 *
35 * Only one callback can be scheduled at a time; scheduling a new callback
36 * cancels any previously scheduled callback.
37 */
38class MAYAFLUX_API Timer {
39public:
40 /**
41 * @brief Constructs a Timer with the specified scheduler
42 * @param scheduler The TaskScheduler that will manage this timer
43 *
44 * Creates a new Timer that will use the provided scheduler for
45 * timing operations. The scheduler provides the sample clock and
46 * task management infrastructure needed for precise timing.
47 */
48 Timer(Vruta::TaskScheduler& scheduler);
49 ~Timer() = default;
50
51 /**
52 * @brief Schedules a callback to execute after a delay
53 * @param delay_seconds Time to wait before executing the callback (in seconds)
54 * @param callback Function to execute after the delay
55 *
56 * This method schedules the provided callback to execute after exactly
57 * the specified delay. If a callback is already scheduled, it is cancelled
58 * and replaced with the new one.
59 *
60 * The timing is sample-accurate, ensuring that the callback executes at
61 * precisely the right moment in the processing timeline.
62 */
63 void schedule(double delay_seconds, std::function<void()> callback);
64
65 /**
66 * @brief Cancels any scheduled callback
67 *
68 * This method cancels any currently scheduled callback, preventing it
69 * from executing. If no callback is scheduled, this method has no effect.
70 */
71 void cancel();
72
73 /**
74 * @brief Checks if a callback is currently scheduled
75 * @return True if a callback is scheduled, false otherwise
76 *
77 * This method returns true if the timer has an active callback scheduled
78 * to execute in the future, and false otherwise.
79 */
80 [[nodiscard]] inline bool is_active() const { return m_active; }
81
82private:
83 /**
84 * @brief Reference to the scheduler that manages this timer
85 *
86 * The scheduler provides the timing infrastructure needed to
87 * execute callbacks at precise sample positions.
88 */
90
91 /**
92 * @brief The underlying computational routine that implements the timer
93 *
94 * This coroutine handles the actual timing and callback execution.
95 * It's created when schedule() is called and destroyed when the
96 * callback executes or cancel() is called.
97 */
98 std::shared_ptr<Vruta::SoundRoutine> m_routine;
99
100 /**
101 * @brief Flag indicating whether a callback is currently scheduled
102 *
103 * This flag is set to true when schedule() is called and reset to
104 * false when the callback executes or cancel() is called.
105 */
107
108 /**
109 * @brief The callback function to execute when the timer fires
110 *
111 * This function is stored when schedule() is called and executed
112 * when the timer fires. It's cleared when cancel() is called.
113 */
114 std::function<void()> m_callback;
115};
116
117/**
118 * @class TimedAction
119 * @brief Utility for executing actions with a start and end function over a duration
120 *
121 * The TimedAction class provides a way to execute a pair of functions with a
122 * specified time interval between them. This is useful for operations that need
123 * to start and then automatically stop after a duration, such as activating a process,
124 * applying a transformation, or implementing any time-bounded state change.
125 *
126 * Example usage:
127 * ```cpp
128 * // Create a timed action
129 * TimedAction action(*scheduler);
130 *
131 * // Execute an action that lasts for 3 seconds
132 * action.execute(
133 * []() { std::cout << "Starting action" << std::endl; },
134 * []() { std::cout << "Ending action" << std::endl; },
135 * 3.0
136 * );
137 * ```
138 *
139 * Only one action can be active at a time; executing a new action cancels
140 * any previously active action.
141 */
142class MAYAFLUX_API TimedAction {
143public:
144 /**
145 * @brief Constructs a TimedAction with the specified scheduler
146 * @param scheduler The TaskScheduler that will manage this action
147 *
148 * Creates a new TimedAction that will use the provided scheduler for
149 * timing operations. The scheduler provides the sample clock and
150 * task management infrastructure needed for precise timing.
151 */
153 ~TimedAction() = default;
154
155 /**
156 * @brief Executes a pair of functions with a time interval between them
157 * @param start_func Function to execute immediately
158 * @param end_func Function to execute after the duration
159 * @param duration_seconds Time between start_func and end_func (in seconds)
160 *
161 * This method executes start_func immediately, then schedules end_func
162 * to execute after the specified duration. This creates a timed action
163 * that starts now and automatically ends after the duration.
164 *
165 * If an action is already in progress, it is cancelled before starting
166 * the new one.
167 */
168 void execute(std::function<void()> start_func, std::function<void()> end_func, double duration_seconds);
169
170 /**
171 * @brief Cancels any active action
172 *
173 * This method cancels any currently active action, preventing the end
174 * function from executing. If no action is active, this method has no effect.
175 */
176 void cancel();
177
178 /**
179 * @brief Checks if an action is currently in progress
180 * @return True if an action is in progress, false otherwise
181 *
182 * This method returns true if an action has been started but not yet
183 * completed or cancelled, and false otherwise.
184 */
185 [[nodiscard]] bool is_pending() const;
186
187private:
188 /**
189 * @brief Reference to the scheduler that manages this action
190 *
191 * The scheduler provides the timing infrastructure needed to
192 * execute the end function at the right time.
193 */
195
196 /**
197 * @brief The timer used to schedule the end function
198 *
199 * This timer is used to execute the end function after the
200 * specified duration has elapsed.
201 */
203};
204
205/**
206 * @class NodeTimer
207 * @brief Specialized timer for controlling computational nodes with precise timing
208 *
209 * The NodeTimer class provides a convenient way to activate processing nodes for
210 * specific durations with sample-accurate timing. It handles the details
211 * of connecting and disconnecting nodes from the processing graph at precisely
212 * the right moments.
213 *
214 * This is particularly useful for activating temporary processes, applying time-limited
215 * transformations, or creating precisely timed events in any computational domain.
216 *
217 * NOTE: As this class is centered around audio playback,
218 * it enforces use of AUDIO_RATE processing token that cant be overridden.
219 *
220 * Example usage:
221 * ```cpp
222 * // Create a node timer
223 * NodeTimer timer(*scheduler, *graph_manager);
224 *
225 * // Activate a processing node for exactly 2 seconds
226 * timer.play_for(process_node, 2.0);
227 * ```
228 *
229 * Only one node can be active at a time; activating a new node cancels
230 * any previously active node.
231 */
232class MAYAFLUX_API NodeTimer {
233public:
234 /**
235 * @brief Constructs a NodeTimer with the specified scheduler
236 * @param scheduler The TaskScheduler that will manage this timer
237 *
238 * Creates a new NodeTimer that will use the provided scheduler for
239 * timing operations. The scheduler provides the sample clock and
240 * task management infrastructure needed for precise timing.
241 */
243
244 /**
245 * @brief Constructs a NodeTimer with the specified scheduler and graph manager
246 * @param scheduler The TaskScheduler that will manage this timer
247 * @param graph_manager The NodeGraphManager that will manage the processing nodes
248 *
249 * Creates a new NodeTimer that will use the provided scheduler and
250 * graph manager for timing and node management operations.
251 */
252 NodeTimer(Vruta::TaskScheduler& scheduler, Nodes::NodeGraphManager& graph_manager);
253 ~NodeTimer() = default;
254
255 /**
256 * @brief Activates a processing node for a specific duration
257 * @param node The processing node to activate
258 * @param duration_seconds How long to keep the node active (in seconds)
259 * @param channels The output channels to connect the node to
260 * @param channel The output channel to connect the node to (single-channel overload)
261 *
262 * This method connects the specified node to the output channel,
263 * activates it for the specified duration, then automatically disconnects it.
264 * The timing is sample-accurate, ensuring that the node remains active for
265 * exactly the right duration.
266 *
267 * If a node is already active, it is deactivated before starting the new one.
268 */
269 void play_for(std::shared_ptr<Nodes::Node> node, double duration_seconds, std::vector<uint32_t> channels);
270 void play_for(std::shared_ptr<Nodes::Node> node, double duration_seconds, uint32_t channel);
271 void play_for(std::shared_ptr<Nodes::Node> node, double duration_seconds);
272
273 /**
274 * @brief Activates a processing node with custom setup and cleanup functions
275 * @param node The processing node to activate
276 * @param setup_func Function to call before activating the node
277 * @param cleanup_func Function to call after deactivating the node
278 * @param duration_seconds How long to keep the node active (in seconds)
279 * @param channels The output channel to connect the node to
280 * @param channel The output channel to connect the node to (single-channel overload)
281 *
282 * This method provides more control over the node activation process by
283 * allowing custom setup and cleanup functions. The setup function is
284 * called before connecting the node, and the cleanup function is called
285 * after disconnecting it.
286 *
287 * This is useful for more complex scenarios where additional setup or
288 * cleanup steps are needed, such as configuring node parameters or
289 * managing resources.
290 *
291 * If a node is already active, it is deactivated before starting the new one.
292 */
293 void play_with_processing(std::shared_ptr<Nodes::Node> node,
294 std::function<void(std::shared_ptr<Nodes::Node>)> setup_func,
295 std::function<void(std::shared_ptr<Nodes::Node>)> cleanup_func,
296 double duration_seconds, std::vector<uint32_t> channels);
297
298 void play_with_processing(std::shared_ptr<Nodes::Node> node,
299 std::function<void(std::shared_ptr<Nodes::Node>)> setup_func,
300 std::function<void(std::shared_ptr<Nodes::Node>)> cleanup_func,
301 double duration_seconds, uint32_t channel);
302
303 void play_with_processing(std::shared_ptr<Nodes::Node> node,
304 std::function<void(std::shared_ptr<Nodes::Node>)> setup_func,
305 std::function<void(std::shared_ptr<Nodes::Node>)> cleanup_func,
306 double duration_seconds);
307
308 /**
309 * @brief Cancels any currently active node
310 *
311 * This method deactivates any currently active node, disconnecting it from
312 * the output channel. If no node is active, this method has no effect.
313 */
314 void cancel();
315
316 /**
317 * @brief Checks if a node is currently active
318 * @return True if a node is active, false otherwise
319 *
320 * This method returns true if the timer has an active node that's
321 * currently processing, and false otherwise.
322 */
323 [[nodiscard]] inline bool is_active() const { return m_timer.is_active(); }
324
325private:
326 /**
327 * @brief Reference to the scheduler that manages this timer
328 *
329 * The scheduler provides the timing infrastructure needed for
330 * precise control of node activation durations.
331 */
333
334 /**
335 * @brief Cleans up the current operation, disconnecting the node and resetting state
336 *
337 * This method is called when the timer completes its specified duration.
338 * It disconnects the currently active node from the output channels and
339 * resets internal state to allow new operations to be started.
340 */
341 void cleanup_current_operation();
342
343 /**
344 * @brief Reference to the graph manager that manages processing nodes
345 *
346 * The graph manager provides the infrastructure for connecting
347 * and disconnecting nodes from the processing graph.
348 */
350
351 /**
352 * @brief The timer used to schedule node disconnection
353 *
354 * This timer is used to disconnect the node after the
355 * specified duration has elapsed.
356 */
358
359 /**
360 * @brief The currently active node being played
361 *
362 * This pointer holds the node that is currently being played.
363 * It is set when play_for() or play_with_processing() is called
364 * and reset when the node finishes playing or is cancelled.
365 */
366 std::shared_ptr<Nodes::Node> m_current_node;
367
368 /**
369 * @brief The output channels the current node is connected to
370 *
371 * This vector stores the output channel numbers that the current
372 * node is connected to. It is set when play_for() or play_with_processing()
373 * is called and reset when the node finishes playing or is cancelled.
374 */
375 std::vector<uint32_t> m_channels;
376};
377
378}
std::shared_ptr< Nodes::Node > m_current_node
The currently active node being played.
Definition Timers.hpp:366
Nodes::NodeGraphManager & m_node_graph_manager
Reference to the graph manager that manages processing nodes.
Definition Timers.hpp:349
Vruta::TaskScheduler & m_scheduler
Reference to the scheduler that manages this timer.
Definition Timers.hpp:332
bool is_active() const
Checks if a node is currently active.
Definition Timers.hpp:323
std::vector< uint32_t > m_channels
The output channels the current node is connected to.
Definition Timers.hpp:375
Timer m_timer
The timer used to schedule node disconnection.
Definition Timers.hpp:357
Specialized timer for controlling computational nodes with precise timing.
Definition Timers.hpp:232
Vruta::TaskScheduler & m_Scheduler
Reference to the scheduler that manages this action.
Definition Timers.hpp:194
Timer m_timer
The timer used to schedule the end function.
Definition Timers.hpp:202
Utility for executing actions with a start and end function over a duration.
Definition Timers.hpp:142
bool m_active
Flag indicating whether a callback is currently scheduled.
Definition Timers.hpp:106
bool is_active() const
Checks if a callback is currently scheduled.
Definition Timers.hpp:80
std::function< void()> m_callback
The callback function to execute when the timer fires.
Definition Timers.hpp:114
Vruta::TaskScheduler & m_Scheduler
Reference to the scheduler that manages this timer.
Definition Timers.hpp:89
std::shared_ptr< Vruta::SoundRoutine > m_routine
The underlying computational routine that implements the timer.
Definition Timers.hpp:98
High-level utility for scheduling one-shot timed callbacks.
Definition Timers.hpp:38
Central manager for the computational processing node graph.
Token-based multimodal task scheduling system for unified coroutine processing.
Definition Scheduler.hpp:51
Contains the node-based computational processing system components.
Definition Chronie.hpp:5