MayaFlux 0.2.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Routine.cpp
Go to the documentation of this file.
1#include "Routine.hpp"
3
4namespace MayaFlux::Vruta {
5
7{
8 return { std::coroutine_handle<audio_promise>::from_promise(*this) };
9}
10
12{
13 return { std::coroutine_handle<graphics_promise>::from_promise(*this) };
14}
15
16SoundRoutine::SoundRoutine(std::coroutine_handle<promise_type> h)
17 : m_handle(h)
18{
19 if (!m_handle || !m_handle.address()) {
20 error<std::invalid_argument>(Journal::Component::Vruta, Journal::Context::CoroutineScheduling, std::source_location::current(),
21 "SoundRoutine constructed with invalid coroutine handle");
22 }
23}
24
26 : m_handle(nullptr)
27{
28 if (other.m_handle) {
29 m_handle = other.m_handle;
30 }
31}
32
34{
35 if (this != &other) {
36 if (m_handle) {
37 m_handle.destroy();
38 }
39
40 if (other.m_handle) {
41 m_handle = other.m_handle;
42 } else {
43 m_handle = nullptr;
44 }
45 }
46 return *this;
47}
48
50 : m_handle(std::exchange(other.m_handle, {}))
51{
52}
53
55{
56 if (this != &other) {
57 if (m_handle && m_handle.address())
58 m_handle.destroy();
59
60 m_handle = std::exchange(other.m_handle, {});
61 }
62 return *this;
63}
64
66{
67 if (m_handle && m_handle.address())
68 m_handle.destroy();
69}
70
72{
73 if (!m_handle) {
75 }
76 return m_handle.promise().processing_token;
77}
78
80{
81 if (!m_handle) {
82 return false;
83 }
84 return m_handle.address() != nullptr && !m_handle.done();
85}
86
87bool SoundRoutine::initialize_state(uint64_t current_sample)
88{
89 if (!m_handle || !m_handle.address() || m_handle.done()) {
90 return false;
91 }
92
93 m_handle.promise().next_sample = current_sample;
94 m_handle.promise().next_buffer_cycle = current_sample;
95 m_handle.resume();
96 return true;
97}
98
100{
101 return is_active() ? m_handle.promise().next_sample : UINT64_MAX;
102}
103
105{
106 if (!m_handle) {
107 return false;
108 }
109 return m_handle.promise().sync_to_clock;
110}
111
112bool SoundRoutine::try_resume_with_context(uint64_t current_value, DelayContext context)
113{
114 if (!is_active())
115 return false;
116
117 auto& promise_ref = m_handle.promise();
118
119 if (promise_ref.should_terminate || !promise_ref.auto_resume) {
120 return false;
121 }
122
123 if (context != DelayContext::NONE && promise_ref.active_delay_context == DelayContext::AWAIT) {
124 return initialize_state(current_value);
125 }
126
127 if (promise_ref.active_delay_context != DelayContext::NONE && promise_ref.active_delay_context != context) {
128 return false;
129 }
130
131 bool should_resume = false;
132
133 switch (context) {
135 if (promise_ref.active_delay_context == DelayContext::SAMPLE_BASED) {
136 should_resume = (current_value >= promise_ref.next_sample);
137 if (should_resume) {
138 promise_ref.next_sample = current_value + promise_ref.delay_amount;
139 }
140 } else {
141 should_resume = false;
142 }
143 break;
144
146 if (promise_ref.active_delay_context == DelayContext::BUFFER_BASED) {
147 should_resume = (current_value >= promise_ref.next_buffer_cycle);
148
149 if (should_resume) {
150 promise_ref.next_buffer_cycle = current_value + promise_ref.delay_amount;
151 }
152 } else {
153 should_resume = false;
154 }
155 break;
156
158 should_resume = true;
159 break;
160
161 default:
162 return false;
163 }
164
165 if (should_resume) {
166 m_handle.resume();
167 return true;
168 }
169
170 return false;
171}
172
173bool SoundRoutine::try_resume(uint64_t current_context)
174{
176}
177
179{
180 if (!m_handle || m_handle.done()) {
181 return false;
182 }
183 m_handle.resume();
184 return true;
185}
186
188{
189 if (!m_handle)
190 return false;
191
192 set_state<bool>("restart", true);
193 m_handle.promise().auto_resume = true;
194 if (is_active()) {
195 m_handle.resume();
196 return true;
197 }
198 return false;
199}
200
201void SoundRoutine::set_state_impl(const std::string& key, std::any value)
202{
203 if (m_handle) {
204 m_handle.promise().state[key] = std::move(value);
205 }
206}
207
208void* SoundRoutine::get_state_impl_raw(const std::string& key)
209{
210 if (!m_handle) {
211 return nullptr;
212 }
213
214 auto& state_map = m_handle.promise().state;
215 auto it = state_map.find(key);
216 if (it != state_map.end()) {
217 return &it->second;
218 }
219 return nullptr;
220}
221
222GraphicsRoutine::GraphicsRoutine(std::coroutine_handle<promise_type> h)
223 : m_handle(h)
224{
225 if (!m_handle || !m_handle.address()) {
226 error<std::invalid_argument>(Journal::Component::Vruta, Journal::Context::CoroutineScheduling, std::source_location::current(),
227 "GraphicsRoutine constructed with invalid coroutine handle");
228 }
229}
230
232 : m_handle(other.m_handle)
233{
234}
235
237{
238 if (this != &other) {
239 m_handle = other.m_handle;
240 }
241 return *this;
242}
243
245 : m_handle(std::exchange(other.m_handle, nullptr))
246{
247}
248
250{
251 if (this != &other) {
252 m_handle = std::exchange(other.m_handle, nullptr);
253 }
254 return *this;
255}
256
258{
259 if (m_handle) {
260 m_handle.destroy();
261 }
262}
263
268
270{
271 return m_handle && !m_handle.done();
272}
273
274bool GraphicsRoutine::initialize_state(uint64_t current_frame)
275{
276 if (!is_active() || !m_handle.address()) {
277 return false;
278 }
279
280 m_handle.promise().next_frame = current_frame;
281 m_handle.resume();
282 return true;
283}
284
286{
287 return m_handle ? m_handle.promise().next_frame : UINT64_MAX;
288}
289
291{
292 if (!m_handle) {
293 return false;
294 }
295 return m_handle.promise().sync_to_clock;
296}
297
298bool GraphicsRoutine::try_resume_with_context(uint64_t current_value, DelayContext context)
299{
300 if (!is_active())
301 return false;
302
303 auto& promise_ref = m_handle.promise();
304
305 if (promise_ref.should_terminate || !promise_ref.auto_resume) {
306 return false;
307 }
308
309 if (context != DelayContext::NONE && promise_ref.active_delay_context == DelayContext::AWAIT) {
310 return initialize_state(current_value);
311 }
312
313 if (promise_ref.active_delay_context != DelayContext::NONE && promise_ref.active_delay_context != context) {
314 return false;
315 }
316
317 bool should_resume = false;
318
319 switch (context) {
321 if (promise_ref.active_delay_context == DelayContext::FRAME_BASED) {
322 should_resume = (current_value >= promise_ref.next_frame);
323 if (should_resume) {
324 promise_ref.next_frame = current_value + promise_ref.delay_amount;
325 }
326 } else {
327 should_resume = false;
328 }
329 break;
330
332 should_resume = true;
333 break;
334
335 default:
336 return false;
337 }
338
339 if (should_resume) {
340 m_handle.resume();
341 return true;
342 }
343
344 return false;
345}
346
347bool GraphicsRoutine::try_resume(uint64_t current_context)
348{
349 // Default to FRAME_BASED context for backwards compatibility
350 // Note: You'll need to add FRAME_BASED to the DelayContext enum
351 return try_resume_with_context(current_context, DelayContext::FRAME_BASED);
352}
353
355{
356 if (!m_handle || m_handle.done()) {
357 return false;
358 }
359 m_handle.resume();
360 return true;
361}
362
364{
365 if (!m_handle)
366 return false;
367
368 set_state<bool>("restart", true);
369 m_handle.promise().auto_resume = true;
370 if (is_active()) {
371 m_handle.resume();
372 return true;
373 }
374 return false;
375}
376
377void GraphicsRoutine::set_state_impl(const std::string& key, std::any value)
378{
379 if (m_handle) {
380 m_handle.promise().state[key] = std::move(value);
381 }
382}
383
384void* GraphicsRoutine::get_state_impl_raw(const std::string& key)
385{
386 if (!m_handle) {
387 return nullptr;
388 }
389
390 auto& state_map = m_handle.promise().state;
391 auto it = state_map.find(key);
392 if (it != state_map.end()) {
393 return &it->second;
394 }
395 return nullptr;
396}
397
398}
void * get_state_impl_raw(const std::string &key) override
Definition Routine.cpp:384
bool force_resume() override
Force resume the coroutine, bypassing all checks Used only during shutdown to push coroutines to fina...
Definition Routine.cpp:354
bool initialize_state(uint64_t current_frame=0U) override
Initializes the coroutine's state for execution.
Definition Routine.cpp:274
void set_state_impl(const std::string &key, std::any value) override
Definition Routine.cpp:377
bool try_resume_with_context(uint64_t current_value, DelayContext context) override
Attempts to resume the coroutine with explicit temporal context.
Definition Routine.cpp:298
bool is_active() const override
Checks if the coroutine is still active.
Definition Routine.cpp:269
bool requires_clock_sync() const override
Check if the routine should synchronize with a clock.
Definition Routine.cpp:290
GraphicsRoutine & operator=(const GraphicsRoutine &other)
Copy assignment operator.
Definition Routine.cpp:236
bool restart() override
Restarts the coroutine from the beginning.
Definition Routine.cpp:363
uint64_t next_execution() const override
Gets the sample position when this routine should next execute.
Definition Routine.cpp:285
std::coroutine_handle< promise_type > m_handle
Handle to the underlying coroutine.
Definition Routine.hpp:654
bool try_resume(uint64_t current_context) override
Attempts to resume the coroutine if it's ready to execute.
Definition Routine.cpp:347
ProcessingToken get_processing_token() const override
Get the processing token that determines how this routine should be scheduled.
Definition Routine.cpp:264
GraphicsRoutine(std::coroutine_handle< promise_type > h)
Constructs a GraphicsRoutine from a coroutine handle.
Definition Routine.cpp:222
A C++20 coroutine-based graphics processing task with frame-accurate timing.
Definition Routine.hpp:513
std::coroutine_handle< promise_type > m_handle
Handle to the underlying coroutine.
Definition Routine.hpp:469
bool is_active() const override
Checks if the coroutine is still active.
Definition Routine.cpp:79
bool try_resume_with_context(uint64_t current_value, DelayContext context) override
Attempts to resume the coroutine with explicit temporal context.
Definition Routine.cpp:112
void * get_state_impl_raw(const std::string &key) override
Definition Routine.cpp:208
uint64_t next_execution() const override
Gets the sample position when this routine should next execute.
Definition Routine.cpp:99
void set_state_impl(const std::string &key, std::any value) override
Definition Routine.cpp:201
bool requires_clock_sync() const override
Check if the routine should synchronize with a clock.
Definition Routine.cpp:104
bool try_resume(uint64_t current_context) override
Attempts to resume the coroutine if it's ready to execute.
Definition Routine.cpp:173
bool force_resume() override
Force resume the coroutine, bypassing all checks Used only during shutdown to push coroutines to fina...
Definition Routine.cpp:178
SoundRoutine(std::coroutine_handle< promise_type > h)
Constructs a SoundRoutine from a coroutine handle.
Definition Routine.cpp:16
SoundRoutine & operator=(const SoundRoutine &other)
Copy assignment operator.
Definition Routine.cpp:33
bool restart() override
Restarts the coroutine from the beginning.
Definition Routine.cpp:187
ProcessingToken get_processing_token() const override
Get the processing token that determines how this routine should be scheduled.
Definition Routine.cpp:71
bool initialize_state(uint64_t current_sample=0U) override
Initializes the coroutine's state for execution.
Definition Routine.cpp:87
A C++20 coroutine-based audio processing task with sample-accurate timing.
Definition Routine.hpp:316
@ CoroutineScheduling
Coroutine scheduling and temporal coordination (Vruta::TaskScheduler)
@ Vruta
Coroutines, schedulers, clocks, task management.
@ FRAME_ACCURATE
Coroutine is frame-accurate.
@ ON_DEMAND
Coroutine is executed on demand, not scheduled.
DelayContext
Discriminator for different temporal delay mechanisms.
@ FRAME_BASED
Frame-rate delay (Graphics domain)
@ NONE
No active delay, resume immediately.
@ SAMPLE_BASED
Sample-accurate delay (audio domain)
@ BUFFER_BASED
Buffer-cycle delay (audio hardware boundary)
@ AWAIT
Awaiter-induced delay (temporary suspension)
SoundRoutine get_return_object()
Creates the SoundRoutine object returned to the caller.
Definition Routine.cpp:6
GraphicsRoutine get_return_object()
Creates the GraphicsRoutine object returned to the caller.
Definition Routine.cpp:11