MayaFlux 0.1.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)
181 return false;
182
183 set_state<bool>("restart", true);
184 m_handle.promise().auto_resume = true;
185 if (is_active()) {
186 m_handle.resume();
187 return true;
188 }
189 return false;
190}
191
192void SoundRoutine::set_state_impl(const std::string& key, std::any value)
193{
194 if (m_handle) {
195 m_handle.promise().state[key] = std::move(value);
196 }
197}
198
199void* SoundRoutine::get_state_impl_raw(const std::string& key)
200{
201 if (!m_handle) {
202 return nullptr;
203 }
204
205 auto& state_map = m_handle.promise().state;
206 auto it = state_map.find(key);
207 if (it != state_map.end()) {
208 return &it->second;
209 }
210 return nullptr;
211}
212
213GraphicsRoutine::GraphicsRoutine(std::coroutine_handle<promise_type> h)
214 : m_handle(h)
215{
216 if (!m_handle || !m_handle.address()) {
217 error<std::invalid_argument>(Journal::Component::Vruta, Journal::Context::CoroutineScheduling, std::source_location::current(),
218 "GraphicsRoutine constructed with invalid coroutine handle");
219 }
220}
221
223 : m_handle(other.m_handle)
224{
225}
226
228{
229 if (this != &other) {
230 m_handle = other.m_handle;
231 }
232 return *this;
233}
234
236 : m_handle(std::exchange(other.m_handle, nullptr))
237{
238}
239
241{
242 if (this != &other) {
243 m_handle = std::exchange(other.m_handle, nullptr);
244 }
245 return *this;
246}
247
249{
250 if (m_handle) {
251 m_handle.destroy();
252 }
253}
254
259
261{
262 return m_handle && !m_handle.done();
263}
264
265bool GraphicsRoutine::initialize_state(uint64_t current_frame)
266{
267 if (!is_active() || !m_handle.address()) {
268 return false;
269 }
270
271 m_handle.promise().next_frame = current_frame;
272 m_handle.resume();
273 return true;
274}
275
277{
278 return m_handle ? m_handle.promise().next_frame : UINT64_MAX;
279}
280
282{
283 if (!m_handle) {
284 return false;
285 }
286 return m_handle.promise().sync_to_clock;
287}
288
289bool GraphicsRoutine::try_resume_with_context(uint64_t current_value, DelayContext context)
290{
291 if (!is_active())
292 return false;
293
294 auto& promise_ref = m_handle.promise();
295
296 if (promise_ref.should_terminate || !promise_ref.auto_resume) {
297 return false;
298 }
299
300 if (context != DelayContext::NONE && promise_ref.active_delay_context == DelayContext::AWAIT) {
301 return initialize_state(current_value);
302 }
303
304 if (promise_ref.active_delay_context != DelayContext::NONE && promise_ref.active_delay_context != context) {
305 return false;
306 }
307
308 bool should_resume = false;
309
310 switch (context) {
312 if (promise_ref.active_delay_context == DelayContext::FRAME_BASED) {
313 should_resume = (current_value >= promise_ref.next_frame);
314 if (should_resume) {
315 promise_ref.next_frame = current_value + promise_ref.delay_amount;
316 }
317 } else {
318 should_resume = false;
319 }
320 break;
321
323 should_resume = true;
324 break;
325
326 default:
327 return false;
328 }
329
330 if (should_resume) {
331 m_handle.resume();
332 return true;
333 }
334
335 return false;
336}
337
338bool GraphicsRoutine::try_resume(uint64_t current_context)
339{
340 // Default to FRAME_BASED context for backwards compatibility
341 // Note: You'll need to add FRAME_BASED to the DelayContext enum
342 return try_resume_with_context(current_context, DelayContext::FRAME_BASED);
343}
344
346{
347 if (!m_handle)
348 return false;
349
350 set_state<bool>("restart", true);
351 m_handle.promise().auto_resume = true;
352 if (is_active()) {
353 m_handle.resume();
354 return true;
355 }
356 return false;
357}
358
359void GraphicsRoutine::set_state_impl(const std::string& key, std::any value)
360{
361 if (m_handle) {
362 m_handle.promise().state[key] = std::move(value);
363 }
364}
365
366void* GraphicsRoutine::get_state_impl_raw(const std::string& key)
367{
368 if (!m_handle) {
369 return nullptr;
370 }
371
372 auto& state_map = m_handle.promise().state;
373 auto it = state_map.find(key);
374 if (it != state_map.end()) {
375 return &it->second;
376 }
377 return nullptr;
378}
379
380}
void * get_state_impl_raw(const std::string &key) override
Definition Routine.cpp:366
bool initialize_state(uint64_t current_frame=0U) override
Initializes the coroutine's state for execution.
Definition Routine.cpp:265
void set_state_impl(const std::string &key, std::any value) override
Definition Routine.cpp:359
bool try_resume_with_context(uint64_t current_value, DelayContext context) override
Attempts to resume the coroutine with explicit temporal context.
Definition Routine.cpp:289
bool is_active() const override
Checks if the coroutine is still active.
Definition Routine.cpp:260
bool requires_clock_sync() const override
Check if the routine should synchronize with a clock.
Definition Routine.cpp:281
GraphicsRoutine & operator=(const GraphicsRoutine &other)
Copy assignment operator.
Definition Routine.cpp:227
bool restart() override
Restarts the coroutine from the beginning.
Definition Routine.cpp:345
uint64_t next_execution() const override
Gets the sample position when this routine should next execute.
Definition Routine.cpp:276
std::coroutine_handle< promise_type > m_handle
Handle to the underlying coroutine.
Definition Routine.hpp:643
bool try_resume(uint64_t current_context) override
Attempts to resume the coroutine if it's ready to execute.
Definition Routine.cpp:338
ProcessingToken get_processing_token() const override
Get the processing token that determines how this routine should be scheduled.
Definition Routine.cpp:255
GraphicsRoutine(std::coroutine_handle< promise_type > h)
Constructs a GraphicsRoutine from a coroutine handle.
Definition Routine.cpp:213
A C++20 coroutine-based graphics processing task with frame-accurate timing.
Definition Routine.hpp:504
std::coroutine_handle< promise_type > m_handle
Handle to the underlying coroutine.
Definition Routine.hpp:460
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:199
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:192
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
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:178
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:309
@ 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