MayaFlux 0.4.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 } else {
149 should_resume = false;
150 }
151 break;
152
154 should_resume = true;
155 break;
156
157 default:
158 return false;
159 }
160
161 if (should_resume) {
162 m_handle.resume();
163 return true;
164 }
165
166 return false;
167}
168
169bool SoundRoutine::try_resume(uint64_t current_context)
170{
172}
173
175{
176 if (!m_handle || m_handle.done()) {
177 return false;
178 }
179 m_handle.resume();
180 return true;
181}
182
184{
185 if (!m_handle)
186 return false;
187
188 set_state<bool>("restart", true);
189 m_handle.promise().auto_resume = true;
190 if (is_active()) {
191 m_handle.resume();
192 return true;
193 }
194 return false;
195}
196
197void SoundRoutine::set_state_impl(const std::string& key, std::any value)
198{
199 if (m_handle) {
200 m_handle.promise().state[key] = std::move(value);
201 }
202}
203
204void* SoundRoutine::get_state_impl_raw(const std::string& key)
205{
206 if (!m_handle) {
207 return nullptr;
208 }
209
210 auto& state_map = m_handle.promise().state;
211 auto it = state_map.find(key);
212 if (it != state_map.end()) {
213 return &it->second;
214 }
215 return nullptr;
216}
217
218GraphicsRoutine::GraphicsRoutine(std::coroutine_handle<promise_type> h)
219 : m_handle(h)
220{
221 if (!m_handle || !m_handle.address()) {
222 error<std::invalid_argument>(Journal::Component::Vruta, Journal::Context::CoroutineScheduling, std::source_location::current(),
223 "GraphicsRoutine constructed with invalid coroutine handle");
224 }
225}
226
228 : m_handle(other.m_handle)
229{
230}
231
233{
234 if (this != &other) {
235 m_handle = other.m_handle;
236 }
237 return *this;
238}
239
241 : m_handle(std::exchange(other.m_handle, nullptr))
242{
243}
244
246{
247 if (this != &other) {
248 m_handle = std::exchange(other.m_handle, nullptr);
249 }
250 return *this;
251}
252
254{
255 if (m_handle) {
256 m_handle.destroy();
257 }
258}
259
264
266{
267 return m_handle && !m_handle.done();
268}
269
270bool GraphicsRoutine::initialize_state(uint64_t current_frame)
271{
272 if (!is_active() || !m_handle.address()) {
273 return false;
274 }
275
276 m_handle.promise().next_frame = current_frame;
277 m_handle.resume();
278 return true;
279}
280
282{
283 return m_handle ? m_handle.promise().next_frame : UINT64_MAX;
284}
285
287{
288 if (!m_handle) {
289 return false;
290 }
291 return m_handle.promise().sync_to_clock;
292}
293
294bool GraphicsRoutine::try_resume_with_context(uint64_t current_value, DelayContext context)
295{
296 if (!is_active())
297 return false;
298
299 auto& promise_ref = m_handle.promise();
300
301 if (promise_ref.should_terminate || !promise_ref.auto_resume) {
302 return false;
303 }
304
305 if (context != DelayContext::NONE && promise_ref.active_delay_context == DelayContext::AWAIT) {
306 return initialize_state(current_value);
307 }
308
309 if (promise_ref.active_delay_context != DelayContext::NONE && promise_ref.active_delay_context != context) {
310 return false;
311 }
312
313 bool should_resume = false;
314
315 switch (context) {
317 if (promise_ref.active_delay_context == DelayContext::FRAME_BASED) {
318 should_resume = (current_value >= promise_ref.next_frame);
319 if (should_resume) {
320 promise_ref.next_frame = current_value + promise_ref.delay_amount;
321 }
322 } else {
323 should_resume = false;
324 }
325 break;
326
328 should_resume = true;
329 break;
330
331 default:
332 return false;
333 }
334
335 if (should_resume) {
336 m_handle.resume();
337 return true;
338 }
339
340 return false;
341}
342
343bool GraphicsRoutine::try_resume(uint64_t current_context)
344{
345 // Default to FRAME_BASED context for backwards compatibility
346 // Note: You'll need to add FRAME_BASED to the DelayContext enum
347 return try_resume_with_context(current_context, DelayContext::FRAME_BASED);
348}
349
351{
352 if (!m_handle || m_handle.done()) {
353 return false;
354 }
355 m_handle.resume();
356 return true;
357}
358
360{
361 if (!m_handle)
362 return false;
363
364 set_state<bool>("restart", true);
365 m_handle.promise().auto_resume = true;
366 if (is_active()) {
367 m_handle.resume();
368 return true;
369 }
370 return false;
371}
372
373void GraphicsRoutine::set_state_impl(const std::string& key, std::any value)
374{
375 if (m_handle) {
376 m_handle.promise().state[key] = std::move(value);
377 }
378}
379
380void* GraphicsRoutine::get_state_impl_raw(const std::string& key)
381{
382 if (!m_handle) {
383 return nullptr;
384 }
385
386 auto& state_map = m_handle.promise().state;
387 auto it = state_map.find(key);
388 if (it != state_map.end()) {
389 return &it->second;
390 }
391 return nullptr;
392}
393
394}
uint32_t h
Definition InkPress.cpp:25
void * get_state_impl_raw(const std::string &key) override
Definition Routine.cpp:380
bool force_resume() override
Force resume the coroutine, bypassing all checks Used only during shutdown to push coroutines to fina...
Definition Routine.cpp:350
bool initialize_state(uint64_t current_frame=0U) override
Initializes the coroutine's state for execution.
Definition Routine.cpp:270
void set_state_impl(const std::string &key, std::any value) override
Definition Routine.cpp:373
bool try_resume_with_context(uint64_t current_value, DelayContext context) override
Attempts to resume the coroutine with explicit temporal context.
Definition Routine.cpp:294
bool is_active() const override
Checks if the coroutine is still active.
Definition Routine.cpp:265
bool requires_clock_sync() const override
Check if the routine should synchronize with a clock.
Definition Routine.cpp:286
GraphicsRoutine & operator=(const GraphicsRoutine &other)
Copy assignment operator.
Definition Routine.cpp:232
bool restart() override
Restarts the coroutine from the beginning.
Definition Routine.cpp:359
uint64_t next_execution() const override
Gets the sample position when this routine should next execute.
Definition Routine.cpp:281
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:343
ProcessingToken get_processing_token() const override
Get the processing token that determines how this routine should be scheduled.
Definition Routine.cpp:260
GraphicsRoutine(std::coroutine_handle< promise_type > h)
Constructs a GraphicsRoutine from a coroutine handle.
Definition Routine.cpp:218
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:204
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:197
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:169
bool force_resume() override
Force resume the coroutine, bypassing all checks Used only during shutdown to push coroutines to fina...
Definition Routine.cpp:174
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:183
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