MayaFlux 0.4.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
14
16
17#ifdef MAYAFLUX_PLATFORM_MACOS
18#include <CoreFoundation/CoreFoundation.h>
19#include <unistd.h>
20#endif
21
22#ifdef MAYAFLUX_PLATFORM_WINDOWS
24#endif
25
26#ifdef MAYAFLUX_PLATFORM_LINUX
27#include <csignal>
28#endif
29
30namespace MayaFlux::Core {
31
32//-------------------------------------------------------------------------
33// Initialization and Lifecycle
34//-------------------------------------------------------------------------
35
37 : m_stochastic_engine(new Kinesis::Stochastic::Stochastic(Kinesis::Stochastic::Algorithm::UNIFORM))
38{
39}
40
42{
43 End();
44}
45
46Engine::Engine(Engine&& other) noexcept
47 : m_stream_info(other.m_stream_info)
48 , m_graphics_config(other.m_graphics_config)
49 , m_is_paused(other.m_is_paused)
50 , m_is_initialized(other.m_is_initialized)
51 , m_should_shutdown(other.m_should_shutdown.load())
52 , m_scheduler(std::move(other.m_scheduler))
53 , m_node_graph_manager(std::move(other.m_node_graph_manager))
54 , m_buffer_manager(std::move(other.m_buffer_manager))
55 , m_subsystem_manager(std::move(other.m_subsystem_manager))
56 , m_window_manager(std::move(other.m_window_manager))
57 , m_event_manager(std::move(other.m_event_manager))
58 , m_input_manager(std::move(other.m_input_manager))
59 , m_io_manager(std::move(other.m_io_manager))
60 , m_stochastic_engine(std::move(other.m_stochastic_engine))
61{
62 other.m_is_initialized = false;
63 other.m_is_paused = false;
64}
65
67{
68 if (this != &other) {
69 End();
70
71 m_stream_info = other.m_stream_info;
72 m_graphics_config = other.m_graphics_config;
73
74 m_subsystem_manager = std::move(other.m_subsystem_manager);
75 m_node_graph_manager = std::move(other.m_node_graph_manager);
76 m_buffer_manager = std::move(other.m_buffer_manager);
77 m_scheduler = std::move(other.m_scheduler);
78 m_window_manager = std::move(other.m_window_manager);
79 m_event_manager = std::move(other.m_event_manager);
80 m_input_manager = std::move(other.m_input_manager);
81 m_io_manager = std::move(other.m_io_manager);
82 m_stochastic_engine = std::move(other.m_stochastic_engine);
83
84 m_is_initialized = other.m_is_initialized;
85 m_is_paused = other.m_is_paused;
86 m_should_shutdown = other.m_should_shutdown.load();
87
88 other.m_is_initialized = false;
89 other.m_is_paused = false;
90 }
91 return *this;
92}
93
98
99void Engine::Init(const GlobalStreamInfo& streamInfo)
100{
102}
103
104void Engine::Init(const GlobalStreamInfo& streamInfo, const GlobalGraphicsConfig& graphics_config, const GlobalInputConfig& input_config, const GlobalNetworkConfig& network_config)
105{
107 m_stream_info = streamInfo;
108 m_graphics_config = graphics_config;
109 m_input_config = input_config;
110 m_network_config = network_config;
111
112 m_scheduler = std::make_shared<Vruta::TaskScheduler>(m_stream_info.sample_rate);
113 m_event_manager = std::make_shared<Vruta::EventManager>();
114 m_input_manager = std::make_shared<InputManager>();
115
116 m_buffer_manager = std::make_shared<Buffers::BufferManager>(
120
121 m_node_graph_manager = std::make_shared<Nodes::NodeGraphManager>(
123
124 m_node_graph_manager->set_node_config(m_node_config);
125
126 m_io_manager = std::make_shared<IO::IOManager>(
128
130 m_window_manager = std::make_shared<WindowManager>(m_graphics_config);
131 } else {
132 MF_WARN(Journal::Component::Core, Journal::Context::Init, "No windowing backend selected - running in audio-only mode");
133 }
134
135 m_subsystem_manager = std::make_shared<SubsystemManager>(
137
138 m_subsystem_manager->create_audio_subsystem(m_stream_info);
139
140 m_subsystem_manager->create_graphics_subsystem(m_graphics_config);
141
142 m_subsystem_manager->create_network_subsystem(m_network_config);
143
144 m_subsystem_manager->create_input_subsystem(m_input_config);
145
146 m_buffer_manager->initialize_buffer_service();
147
148 m_is_initialized = true;
149
151}
152
162
164{
166 return;
167 }
168
169 m_subsystem_manager->pause_all_subsystems();
170 m_is_paused = true;
171}
172
174{
175 if (!m_is_paused || !m_is_initialized) {
176 return;
177 }
178
179 m_subsystem_manager->resume_all_subsystems();
180 m_is_paused = false;
181}
182
184{
186 return false;
187 }
188
189 if (m_is_initialized) {
190 auto status = m_subsystem_manager->query_subsystem_status();
191 for (const auto& [type, readiness] : status) {
192 const auto& [is_ready, is_running] = readiness;
193 if (is_ready && is_running) {
194 return true;
195 }
196 }
197 }
198 return false;
199}
200
202{
203#ifdef MAYAFLUX_PLATFORM_MACOS
204 run_macos_event_loop();
205#elif defined(MAYAFLUX_PLATFORM_WINDOWS)
206 static std::atomic<bool> s_signal_received { false };
207 s_signal_received.store(false, std::memory_order_relaxed);
208
209 SetConsoleCtrlHandler([](DWORD type) -> BOOL {
210 if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT || type == CTRL_CLOSE_EVENT) {
211 s_signal_received.store(true, std::memory_order_release);
212 return TRUE;
213 }
214 return FALSE;
215 },
216 TRUE);
217
218 HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
219 bool has_console = h_stdin != INVALID_HANDLE_VALUE && GetFileType(h_stdin) == FILE_TYPE_CHAR;
220
221 if (has_console) {
222 while (!s_signal_received.load(std::memory_order_acquire)
223 && !m_should_shutdown.load(std::memory_order_acquire)) {
224 if (WaitForSingleObject(h_stdin, 100) == WAIT_OBJECT_0) {
225 INPUT_RECORD rec {};
226 DWORD read {};
227 if (ReadConsoleInputW(h_stdin, &rec, 1, &read) && read > 0
228 && rec.EventType == KEY_EVENT
229 && rec.Event.KeyEvent.bKeyDown
230 && rec.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) {
231 break;
232 }
233 }
234 }
235 } else {
236 m_should_shutdown.wait(false);
237 }
238#else
239 static std::atomic<bool> s_signal_received { false };
240 s_signal_received.store(false, std::memory_order_relaxed);
241
242 struct sigaction sa {};
243 sa.sa_handler = [](int) { s_signal_received.store(true, std::memory_order_release); };
244 sigaction(SIGINT, &sa, nullptr);
245 sigaction(SIGTERM, &sa, nullptr);
246
247 bool has_tty = isatty(STDIN_FILENO);
248 if (has_tty) {
249 while (!s_signal_received.load(std::memory_order_acquire)) {
250 fd_set fds;
251 FD_ZERO(&fds);
252 FD_SET(STDIN_FILENO, &fds);
253 timeval tv { .tv_sec = 0, .tv_usec = 100000 };
254 if (select(1, &fds, nullptr, nullptr, &tv) > 0) {
255 char c {};
256 if (read(STDIN_FILENO, &c, 1) > 0 && c == '\n')
257 break;
258 }
259 }
260 } else {
261 sigset_t mask;
262 sigfillset(&mask);
263 sigdelset(&mask, SIGINT);
264 sigdelset(&mask, SIGTERM);
265 sigsuspend(&mask);
266 }
267
268#endif
269
270 m_should_shutdown.store(true, std::memory_order_release);
271
273 "Shutdown requested, awaiting all subsystem termination ......");
274}
275
277{
278 m_should_shutdown.store(true, std::memory_order_release);
279
280#ifdef MAYAFLUX_PLATFORM_MACOS
281 CFRunLoopStop(CFRunLoopGetMain());
282#endif
283}
284
286{
287 return m_should_shutdown.load(std::memory_order_acquire);
288}
289
290#ifdef MAYAFLUX_PLATFORM_MACOS
291void Engine::run_macos_event_loop()
292{
293 CFRunLoopRef runLoop = CFRunLoopGetMain();
294
295 dispatch_source_t stdinSource = dispatch_source_create(
296 DISPATCH_SOURCE_TYPE_READ,
297 STDIN_FILENO,
298 0,
299 dispatch_get_main_queue());
300
301 dispatch_source_set_event_handler(stdinSource, ^{
302 char buf[1024];
303 ssize_t bytes_read = read(STDIN_FILENO, buf, sizeof(buf));
304 if (bytes_read > 0) {
306 }
307 });
308
309 dispatch_resume(stdinSource);
310
311 double timeout_seconds = 1.0 / static_cast<double>(m_graphics_config.target_frame_rate);
312
314 "Main thread event loop running (polling at {}fps)",
316
317 while (!is_shutdown_requested()) {
318 CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout_seconds, false);
319 }
320
321 dispatch_source_cancel(stdinSource);
322 dispatch_release(stdinSource);
323
325 "Main thread event loop exiting");
326}
327#endif
328
330{
331 if (!m_is_initialized)
332 return;
333
335
336 if (m_event_manager) {
337 m_event_manager->terminate_all_events();
338 }
339
341 m_node_graph_manager->terminate_active_processing();
342 }
343
345 m_subsystem_manager->stop();
346 }
347
348 if (m_scheduler) {
349 m_scheduler->terminate_all_tasks();
350 }
351
352 if (m_buffer_manager) {
353 m_buffer_manager->terminate_active_buffers();
354 m_buffer_manager.reset();
355 }
356
357 if (m_window_manager) {
358 m_window_manager->set_terminate();
359 auto windows = m_window_manager->get_windows();
360 for (auto& window : windows) {
361 m_window_manager->destroy_window(window, true);
362 }
363 m_window_manager.reset();
364 }
365
367 m_node_graph_manager.reset();
368 }
369
371 m_subsystem_manager->shutdown();
372 }
373
374 m_is_initialized = false;
375 m_is_paused = false;
376}
377
379{
381 return m_node_graph_manager->get_node_config();
382 }
383
384 return m_node_config;
385}
386
388{
389 m_node_config = config;
391 m_node_graph_manager->set_node_config(config);
392 }
393}
394
395} // namespace MayaFlux::Core
#define MF_INFO(comp, ctx,...)
#define MF_LOG(comp, ctx,...)
#define MF_WARN(comp, ctx,...)
Factory free functions for the Forma surface system.
void Init()
Initializes all system components and prepares for processing.
Definition Engine.cpp:94
std::shared_ptr< SubsystemManager > m_subsystem_manager
Definition Engine.hpp:402
void await_shutdown()
Blocks until shutdown is requested (main thread event loop)
Definition Engine.cpp:201
std::shared_ptr< IO::IOManager > m_io_manager
IO manager for video/audio loading and dispatch.
Definition Engine.hpp:406
GlobalNetworkConfig m_network_config
Network configuration.
Definition Engine.hpp:387
GlobalGraphicsConfig m_graphics_config
Graphics/windowing configuration.
Definition Engine.hpp:385
void request_shutdown()
Request shutdown from any thread.
Definition Engine.cpp:276
void Resume()
Resumes processing from paused state.
Definition Engine.cpp:173
std::shared_ptr< Vruta::EventManager > m_event_manager
Event manager (currently only glfw events)
Definition Engine.hpp:404
std::shared_ptr< Buffers::BufferManager > m_buffer_manager
Buffer manager.
Definition Engine.hpp:401
void set_node_config(const Nodes::NodeConfig &config)
Sets the node processing configuration.
Definition Engine.cpp:387
GlobalStreamInfo m_stream_info
Stream configuration.
Definition Engine.hpp:384
bool is_running() const
Checks if the coordinated processing system is currently active.
Definition Engine.cpp:183
void Start()
Starts the coordinated processing of all subsystems.
Definition Engine.cpp:153
Nodes::NodeConfig & get_node_config()
Gets the current node processing configuration.
Definition Engine.cpp:378
std::atomic< bool > m_should_shutdown
Definition Engine.hpp:393
void Pause()
Pauses all processing while maintaining system state.
Definition Engine.cpp:163
bool m_is_paused
Pause state flag.
Definition Engine.hpp:390
std::shared_ptr< WindowManager > m_window_manager
Window manager (Windowing subsystem)
Definition Engine.hpp:403
Engine()
Constructs a new Engine instance.
Definition Engine.cpp:36
std::shared_ptr< Vruta::TaskScheduler > m_scheduler
Task scheduler.
Definition Engine.hpp:399
std::shared_ptr< InputManager > m_input_manager
Input manager (HID/MIDI/etc.)
Definition Engine.hpp:405
Nodes::NodeConfig m_node_config
Node processing configuration.
Definition Engine.hpp:388
~Engine()
Destroys the Engine instance and cleans up resources.
Definition Engine.cpp:41
bool is_shutdown_requested() const
Check if shutdown has been requested.
Definition Engine.cpp:285
void End()
Stops all processing and performs clean shutdown.
Definition Engine.cpp:329
std::shared_ptr< Nodes::NodeGraphManager > m_node_graph_manager
Node graph manager.
Definition Engine.hpp:400
Engine & operator=(const Engine &)=delete
GlobalInputConfig m_input_config
Input configuration.
Definition Engine.hpp:386
Central lifecycle manager and component orchestrator for the MayaFlux processing system.
Definition Engine.hpp:80
@ Init
Engine/subsystem initialization.
@ Runtime
General runtime operations (default fallback)
@ Core
Core engine, backend, subsystems.
void shutdown()
Release stored references.
Definition Forma.cpp:168
bool initialize(std::shared_ptr< Nodes::NodeGraphManager > node_graph_manager, std::shared_ptr< Buffers::BufferManager > buffer_manager, std::shared_ptr< Vruta::TaskScheduler > scheduler, std::shared_ptr< Vruta::EventManager > event_manager, std::shared_ptr< Core::WindowManager > window_manager)
Store engine-level references for use by all subsequent Forma calls.
Definition Forma.cpp:132
bool initialize()
Initialize Portal::System.
Definition System.cpp:27
constexpr std::string_view enum_to_string(EnumType value) noexcept
Universal enum to string converter using magic_enum (original case)
void End()
Stops and cleans up the default engine.
Definition Core.cpp:146
@ 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.
Configuration for the NetworkSubsystem.
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