Architecture Overview¶
High-level pipeline¶
PipeWire "what you hear" monitor
│ (Rust: native/pwshim, staticlib, statically linked via Native AOT)
▼
PipeWireAudioSource (Audio/) ──▶ RingBuffer ──▶ AudioWindow (tail buffer)
│
▼
IFft.Process() (Shaders/CpuFft.cs or GpuFft.cs,
per --fft-device) windowed FFT →
log-compressed, gravity-smoothed
magnitude spectra (left, right)
│
▼
AudioSpectrumTexture × 2 (1D R32F textures)
│
▼
ShaderModule (GLava module dir: 1.frag, 2.frag, ...)
each pass: fullscreen triangle, samples audio_l/audio_r + tex0
(previous pass's output), renders to ping-pong FBOs, last pass
to the default framebuffer
│
▼
AppWindow: GLFW SwapBuffers
Every frame (AppWindow.Run): pump whatever new PCM PipeWire has produced
into the ring buffer, run one FFT over the most recent window, upload the
two resulting spectra as 1D textures, run the active module's pass chain,
swap buffers.
Project layout¶
GlavaSharp/
├── GlavaSharp.slnx solution file (new XML .slnx format)
├── CMakeLists.txt orchestrates: cargo build (native/pwshim, native/x11shim) → dotnet publish (AOT)
├── .github/workflows/ci.yml CI: rust jobs (pwshim, x11shim), dotnet job, full AOT integration job
├── src/
│ └── GlavaSharp/ the .NET project — all C# source lives here
│ ├── GlavaSharp.csproj
│ ├── Program.cs CLI parsing, wiring, entry point
│ ├── FftSettings.cs
│ ├── GpuEnumerator.cs --list-gpus / --gpu N (DRI_PRIME etc.)
│ ├── Audio/ PipeWire capture (P/Invoke into native/pwshim)
│ ├── Shaders/ FFT, shader preprocessing, module pass pipeline
│ ├── Windowing/ GLFW window/context/frame-loop,
│ │ X11 desktop-mode P/Invoke (X11Native.cs)
│ ├── shaders/glava/ GLava's own shader tree, bundled as-is
│ ├── shaders/glavasharp/ GlavaSharp-original modules (e.g. waterfall) --
│ │ NOT part of GLava's tree, see below
│ └── shaders/fft/ GpuFft's compute kernel(s) -- not a GLava
│ module tree at all, loaded directly by
│ Shaders/GpuFft.cs, not ShaderModule
└── native/
├── pwshim/ standalone Rust crate — NOT nested in the
│ C# project, since it isn't C# code and has
│ its own independent build/test lifecycle
│ ├── Cargo.toml
│ └── src/lib.rs PipeWire stream capture, exposed via a
│ small extern "C" FFI surface
└── x11shim/ same reasoning as pwshim: standalone Rust
crate, statically linked, not nested in
the C# project
├── Cargo.toml
└── src/lib.rs X11 EWMH desktop-mode (--desktop): window
type/state, decorations, geometry,
click-through, and a background
re-lower-on-restack watcher, exposed via
a small extern "C" FFI surface
native/pwshim/ living outside src/GlavaSharp/ (rather than e.g. a
native-rs/ folder nested inside the C# project, which is how this
started out) is deliberate: it's a fully independent build unit with its
own Cargo.lock, its own CI job, and its own release cadence — nesting it
inside the .NET project directory implied an ownership relationship that
doesn't reflect how the two are actually built, versioned, or tested.
native/x11shim/ follows the same reasoning.