Welcome to the internal sanctum. If you're reading this, you're either looking to contribute or you're trying to figure out why we use a VisualizerWindow instead of a simple QOpenGLWidget.
We follow a strict pattern to ensure that the "Arch BTW" levels of cleanliness are maintained.
Located in src/core/Application.hpp.
- Owns all core engines (
AudioEngine,OverlayEngine,VideoRecorder). - Manages the lifecycle. If
Applicationdies, everything dies gracefully. - Accessible via the
APPmacro. No global variables, just a well-managed singleton.
AudioEngine: Coordinates playback and analysis. Feeds PCM data to projectM.OverlayEngine: Manages text quads. It's essentially a mini-rendering engine on top of the visualizer.VideoRecorder: An asynchronous beast. It lives in its own thread because blocking the UI for a frame write is a sin.
- Bridge the gap between the UI (Qt Widgets) and the Engines.
- They handle the signals and slots so the engines don't have to know about the UI.
We don't just "draw" to the screen. We have a pipeline:
- projectM Render: Renders the preset to a Framebuffer Object (FBO).
- Capture (Optional): If recording, we use Pixel Buffer Objects (PBOs) for a double-buffered, zero-copy readback. This keeps the FPS high even while encoding 4K video.
- Overlay Pass: The
OverlayRendererdraws text and graphics over the FBO. - Blit: The final result is blitted to the
VisualizerWindow.
- Main Thread: Qt Event Loop + OpenGL Rendering.
- Audio Thread: Managed by FFmpeg/QtMultimedia.
- Recorder Thread: A dedicated
std::jthreadfor the FFmpeg encoder loop. - Network Thread:
QNetworkAccessManagerhandles Suno API calls without stuttering the visuals.
Senior Dev: "I've banned the new keyword. If I see a raw pointer owning a resource, I'm rejecting the PR. Use std::unique_ptr. Also, vc::Result<T> is not a suggestion, it's the law."
Richard Stallman: "Why are you using OpenGL? You should be using a purely software-based renderer to ensure that no proprietary microcode in the GPU is being executed! And these 'threads'... they are a chaos that defies the deterministic beauty of a single-threaded Lisp environment!"
Linus (LTT): "Richard, if we used a software renderer, we'd be getting 2 frames per minute. This architecture is great because it lets me record at 60fps while my CPU is barely breaking 10% usage. That's what I call performance per watt!"
"Code like the person who has to maintain it is a violent psychopath who knows where you live. Or worse, someone who uses Windows." — The Senior Dev