MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Engine.cpp
Go to the documentation of this file.
1#include "Engine.hpp"
2
11
13
14#ifdef MAYAFLUX_PLATFORM_MACOS
15#include <CoreFoundation/CoreFoundation.h>
16#include <unistd.h>
17#endif
18
19#ifdef MAYAFLUX_PLATFORM_WINDOWS
21#endif
22
23namespace MayaFlux::Core {
24
25//-------------------------------------------------------------------------
26// Initialization and Lifecycle
27//-------------------------------------------------------------------------
28
30 : m_stochastic_engine(new Kinesis::Stochastic::Stochastic(Kinesis::Stochastic::Algorithm::UNIFORM))
31{
32}
33
35{
36 End();
37}
38
39Engine::Engine(Engine&& other) noexcept
40 : m_stream_info(other.m_stream_info)
41 , m_graphics_config(other.m_graphics_config)
42 , m_is_paused(other.m_is_paused)
43 , m_is_initialized(other.m_is_initialized)
44 , m_should_shutdown(other.m_should_shutdown.load())
45 , m_scheduler(std::move(other.m_scheduler))
46 , m_node_graph_manager(std::move(other.m_node_graph_manager))
47 , m_buffer_manager(std::move(other.m_buffer_manager))
48 , m_subsystem_manager(std::move(other.m_subsystem_manager))
49 , m_window_manager(std::move(other.m_window_manager))
50 , m_event_manager(std::move(other.m_event_manager))
51 , m_input_manager(std::move(other.m_input_manager))
52 , m_io_manager(std::move(other.m_io_manager))
53 , m_stochastic_engine(std::move(other.m_stochastic_engine))
54{
55 other.m_is_initialized = false;
56 other.m_is_paused = false;
57}
58
60{
61 if (this != &other) {
62 End();
63
64 m_stream_info = other.m_stream_info;
65 m_graphics_config = other.m_graphics_config;
66
67 m_subsystem_manager = std::move(other.m_subsystem_manager);
68 m_node_graph_manager = std::move(other.m_node_graph_manager);
69 m_buffer_manager = std::move(other.m_buffer_manager);
70 m_scheduler = std::move(other.m_scheduler);
71 m_window_manager = std::move(other.m_window_manager);
72 m_event_manager = std::move(other.m_event_manager);
73 m_input_manager = std::move(other.m_input_manager);
74 m_io_manager = std::move(other.m_io_manager);
75 m_stochastic_engine = std::move(other.m_stochastic_engine);
76
77 m_is_initialized = other.m_is_initialized;
78 m_is_paused = other.m_is_paused;
79 m_should_shutdown = other.m_should_shutdown.load();
80
81 other.m_is_initialized = false;
82 other.m_is_paused = false;
83 }
84 return *this;
85}
86
88{
89#ifdef MAYAFLUX_PLATFORM_WINDOWS
90 if (Parallel::g_MainThreadId == 0) {
91 Parallel::g_MainThreadId = GetCurrentThreadId();
92 }
93#endif // MAYAFLUX_PLATFORM_WINDOWS
94
96}
97
98void Engine::Init(const GlobalStreamInfo& streamInfo)
99{
101}
102
103void Engine::Init(const GlobalStreamInfo& streamInfo, const GlobalGraphicsConfig& graphics_config, const GlobalInputConfig& input_config)
104{
106 m_stream_info = streamInfo;
107 m_graphics_config = graphics_config;
108 m_input_config = input_config;
109
110 m_scheduler = std::make_shared<Vruta::TaskScheduler>(m_stream_info.sample_rate);
111 m_event_manager = std::make_shared<Vruta::EventManager>();
112 m_input_manager = std::make_shared<InputManager>();
113
114 m_buffer_manager = std::make_shared<Buffers::BufferManager>(
118
119 m_node_graph_manager = std::make_shared<Nodes::NodeGraphManager>(m_stream_info.sample_rate, m_stream_info.buffer_size);
120
121 m_node_graph_manager->set_node_config(m_node_config);
122
123 m_io_manager = std::make_shared<IO::IOManager>(
125
127 m_window_manager = std::make_shared<WindowManager>(m_graphics_config);
128 } else {
129 MF_WARN(Journal::Component::Core, Journal::Context::Init, "No windowing backend selected - running in audio-only mode");
130 }
131
132 m_subsystem_manager = std::make_shared<SubsystemManager>(
134
135 m_subsystem_manager->create_audio_subsystem(m_stream_info);
136
137 m_subsystem_manager->create_graphics_subsystem(m_graphics_config);
138
139 m_subsystem_manager->create_input_subsystem(m_input_config);
140
141 m_buffer_manager->initialize_buffer_service();
142
143 m_is_initialized = true;
144
145 MF_PRINT(Journal::Component::Core, Journal::Context::Init, "Audio backend: RtAudio, Sample rate: {}", m_stream_info.sample_rate);
146}
147
149{
150 if (!m_is_initialized) {
151 Init();
152 }
153 m_subsystem_manager->start_all_subsystems();
154}
155
157{
159 return;
160 }
161
162 m_subsystem_manager->pause_all_subsystems();
163 m_is_paused = true;
164}
165
167{
168 if (!m_is_paused || !m_is_initialized) {
169 return;
170 }
171
172 m_subsystem_manager->resume_all_subsystems();
173 m_is_paused = false;
174}
175
177{
179 return false;
180 }
181
182 if (m_is_initialized) {
183 auto status = m_subsystem_manager->query_subsystem_status();
184 for (const auto& [type, readiness] : status) {
185 const auto& [is_ready, is_running] = readiness;
186 if (is_ready && is_running) {
187 return true;
188 }
189 }
190 }
191 return false;
192}
193
195{
196#ifdef MAYAFLUX_PLATFORM_MACOS
197 run_macos_event_loop();
198#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
199 run_windows_event_loop();
200#else
201 // Simple blocking wait on other platforms
202 std::cin.get();
203#endif
204
205 m_should_shutdown.store(true, std::memory_order_release);
206
208 "Shutdown requested, awaiting all subsystem termination ......");
209}
210
212{
213 m_should_shutdown.store(true, std::memory_order_release);
214
215#ifdef MAYAFLUX_PLATFORM_MACOS
216 CFRunLoopStop(CFRunLoopGetMain());
217#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
218 PostThreadMessage(Parallel::g_MainThreadId, WM_QUIT, 0, 0);
219#endif
220}
221
223{
224 return m_should_shutdown.load(std::memory_order_acquire);
225}
226
227#ifdef MAYAFLUX_PLATFORM_MACOS
228void Engine::run_macos_event_loop()
229{
230 CFRunLoopRef runLoop = CFRunLoopGetMain();
231
232 dispatch_source_t stdinSource = dispatch_source_create(
233 DISPATCH_SOURCE_TYPE_READ,
234 STDIN_FILENO,
235 0,
236 dispatch_get_main_queue());
237
238 dispatch_source_set_event_handler(stdinSource, ^{
239 char buf[1024];
240 ssize_t bytes_read = read(STDIN_FILENO, buf, sizeof(buf));
241 if (bytes_read > 0) {
243 }
244 });
245
246 dispatch_resume(stdinSource);
247
248 double timeout_seconds = 1.0 / static_cast<double>(m_graphics_config.target_frame_rate);
249
251 "Main thread event loop running (polling at {}fps)",
253
254 while (!is_shutdown_requested()) {
255 CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout_seconds, false);
256 }
257
258 dispatch_source_cancel(stdinSource);
259 dispatch_release(stdinSource);
260
262 "Main thread event loop exiting");
263}
264#endif
265
266#ifdef MAYAFLUX_PLATFORM_WINDOWS
267void Engine::run_windows_event_loop()
268{
269 MSG msg;
270 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
271
272 auto stdinSource = std::thread([this]() {
273 std::cin.get();
275 });
276
278 "Main thread event loop running");
279
280 while (!is_shutdown_requested()) {
281 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
282 if (msg.message == WM_QUIT) {
284 break;
285 }
286
287 if (msg.message == MAYAFLUX_WM_DISPATCH) {
288 auto* task = reinterpret_cast<std::function<void()>*>(msg.lParam);
289 if (task) {
290 (*task)();
291 delete task;
292 }
293 } else {
294 TranslateMessage(&msg);
295 DispatchMessage(&msg);
296 }
297 }
298
299 std::this_thread::sleep_for(std::chrono::milliseconds(1));
300 }
301
302 if (stdinSource.joinable()) {
303 stdinSource.detach();
304 }
305
307 "Main thread event loop exiting");
308}
309#endif
310
312{
313 if (!m_is_initialized)
314 return;
315
317 m_node_graph_manager->terminate_active_processing();
318 }
319
321 m_subsystem_manager->stop();
322 }
323
324 if (m_scheduler) {
325 m_scheduler->terminate_all_tasks();
326 }
327
328 if (m_buffer_manager) {
329 m_buffer_manager->terminate_active_buffers();
330 m_buffer_manager.reset();
331 }
332
333 if (m_window_manager) {
334 m_window_manager->set_terminate();
335 auto windows = m_window_manager->get_windows();
336 for (auto& window : windows) {
337 m_window_manager->destroy_window(window, true);
338 }
339 m_window_manager.reset();
340 }
341
343 m_node_graph_manager.reset();
344 }
345
347 m_subsystem_manager->shutdown();
348 }
349
350 m_is_initialized = false;
351 m_is_paused = false;
352}
353
355{
357 return m_node_graph_manager->get_node_config();
358 }
359
360 return m_node_config;
361}
362
364{
365 m_node_config = config;
367 m_node_graph_manager->set_node_config(config);
368 }
369}
370
371} // namespace MayaFlux::Core
#define MF_INFO(comp, ctx,...)
#define MF_PRINT(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
void Init()
Initializes all system components and prepares for processing.
Definition Engine.cpp:87
std::shared_ptr< SubsystemManager > m_subsystem_manager
Definition Engine.hpp:383
void await_shutdown()
Blocks until shutdown is requested (main thread event loop)
Definition Engine.cpp:194
std::shared_ptr< IO::IOManager > m_io_manager
IO manager for video/audio loading and dispatch.
Definition Engine.hpp:387
GlobalGraphicsConfig m_graphics_config
Graphics/windowing configuration.
Definition Engine.hpp:367
void request_shutdown()
Request shutdown from any thread.
Definition Engine.cpp:211
void Resume()
Resumes processing from paused state.
Definition Engine.cpp:166
std::shared_ptr< Vruta::EventManager > m_event_manager
Event manager (currently only glfw events)
Definition Engine.hpp:385
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
Buffer manager.
Definition Engine.hpp:382
void set_node_config(const Nodes::NodeConfig &config)
Sets the node processing configuration.
Definition Engine.cpp:363
GlobalStreamInfo m_stream_info
Stream configuration.
Definition Engine.hpp:366
bool is_running() const
Checks if the coordinated processing system is currently active.
Definition Engine.cpp:176
void Start()
Starts the coordinated processing of all subsystems.
Definition Engine.cpp:148
Nodes::NodeConfig & get_node_config()
Gets the current node processing configuration.
Definition Engine.cpp:354
std::atomic< bool > m_should_shutdown
Definition Engine.hpp:374
void Pause()
Pauses all processing while maintaining system state.
Definition Engine.cpp:156
bool m_is_paused
Pause state flag.
Definition Engine.hpp:371
std::shared_ptr< WindowManager > m_window_manager
Window manager (Windowing subsystem)
Definition Engine.hpp:384
Engine()
Constructs a new Engine instance.
Definition Engine.cpp:29
std::shared_ptr< Vruta::TaskScheduler > m_scheduler
Task scheduler.
Definition Engine.hpp:380
std::shared_ptr< InputManager > m_input_manager
Input manager (HID/MIDI/etc.)
Definition Engine.hpp:386
Nodes::NodeConfig m_node_config
Node processing configuration.
Definition Engine.hpp:369
~Engine()
Destroys the Engine instance and cleans up resources.
Definition Engine.cpp:34
bool is_shutdown_requested() const
Check if shutdown has been requested.
Definition Engine.cpp:222
void End()
Stops all processing and performs clean shutdown.
Definition Engine.cpp:311
std::shared_ptr< Nodes::NodeGraphManager > m_node_graph_manager
Node graph manager.
Definition Engine.hpp:381
Engine & operator=(const Engine &)=delete
GlobalInputConfig m_input_config
Input configuration.
Definition Engine.hpp:368
Central lifecycle manager and component orchestrator for the MayaFlux processing system.
Definition Engine.hpp:79
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Core
Core engine, backend, subsystems.
void End()
Stops and cleans up the default engine.
Definition Core.cpp:136
@ NONE
No windowing (offscreen rendering only)
uint32_t target_frame_rate
Target frame rate for visual processing (Hz)
WindowingBackend windowing_backend
Selected windowing backend.
Configuration for the InputSubsystem.
uint32_t channels
Number of discrete channels in this set.
bool enabled
Whether this channel set is active in the stream.
uint32_t buffer_size
Number of samples per processing block.
ChannelConfig input
Configuration for input signal channels (disabled by default)
uint32_t sample_rate
Number of samples processed per second (Hz)
ChannelConfig output
Configuration for output signal channels.
Comprehensive configuration for digital audio stream processing.
Configuration settings for individual audio nodes.
Definition NodeSpec.hpp:29