How horuse/splitwave works
1. Overall shape
Splitwave is a desktop audio router built as a Svelte frontend + Tauri shell + Rust audio engine. The UI lets users assemble an audio graph, while the Rust side owns all real audio I/O, DSP, recording, and OS-specific integration.
2. Frontend boundary
The src/ tree is the presentation layer: SvelteKit routes for the main editor, pipeline detail pages, preview, and virtual-device management. The UI is organized by feature modules such as flow, audio, pipeline, overlay, updater, and error, with shared components and icons underneath src/lib/components.
3. Graph editor and state
The flow module is the visual node editor. It renders inputs, effects, and outputs as nodes, supports undo/redo and snapshot history, and drives the user-facing model of the audio pipeline. The pipeline module holds the typed state model and the generated Rust-backed TypeScript types used by the editor.
4. Frontend-to-backend contract
The app uses Tauri commands as the bridge between UI and engine. Shared pipeline types are generated from Rust (ts-rs-style generated files in src/lib/modules/pipeline/generated), so the frontend and backend agree on node kinds, effect parameters, and recording formats.
5. Rust application core
src-tauri/src/ is the runtime backend. main.rs and lib.rs boot the Tauri app, commands.rs exposes callable operations to the frontend, state.rs stores application state, and error.rs centralizes error propagation back to the UI.
6. Audio engine pipeline
The heart of the system is src-tauri/src/audio/pipeline/ and engine.rs. Audio flows through a DAG-based pipeline where sources are normalized, resampled, processed by effects, and delivered to outputs. Supporting modules handle timing/clocking, worker execution, meters, signal representation, and file reading.
7. Inputs and capture sources
Input acquisition is split by source type and platform:
- capture/ handles system and per-app capture
- device/ handles microphone and speaker device enumeration
- system_audio/ and virtual_device/ manage OS-specific capture/loopback sources
- input_bridge.rs and playback.rs connect captured audio into the processing graph
The backend supports microphones, system audio, per-app capture, file input, and virtual-device loopback as first-class sources.
8. Effects and metering
Effects live in audio/effects/ and are implemented in Rust as DSP modules: gain, mute, balance, EQ, compressor, delay, limiter, noise gate/suppressor, reverb, saturator, LUFS/level metering, and waveform analysis. These are applied inside the pipeline, not in the UI, so the editor only configures them.
9. Outputs and encoders
The output side supports speaker/device playback, virtual-device output, and file recording. audio/encoders/ contains format-specific writers for WAV, FLAC, AIFF, MP3, Opus, and AAC; these are fed by the processed stream when the graph terminates in a recording node.
10. Platform-specific audio boundaries
The backend is heavily OS-conditioned:
- macOS: CoreAudio/HAL for device enumeration, ScreenCaptureKit for system/app capture, cpal for device I/O, and a custom AudioServerPlugin virtual driver.
- Linux: PipeWire for device I/O, capture, playback, and null-sink virtual devices.
- Windows: WASAPI via cpal, plus Windows APIs for loopback/process capture and endpoint volume. Virtual devices are not available.
11. Native macOS support code
src-tauri/native/ contains Swift and C++ support code used only on macOS. Swift is used for ScreenCaptureKit bridging and AAC encoding support, while virtual_driver/ implements the AudioServerPlugin driver that makes virtual devices appear system-wide.
12. Packaging and build-time integration
The repository is packaged as a Tauri desktop app across macOS, Linux, and Windows. build.rs coordinates native build steps, including the macOS Swift/static-library pieces. The CI/release workflows and Tauri config files split the app into platform-specific installers and capabilities.
13. Important data flow for diagrams
The main runtime path is: OS audio sources or file input → backend capture/device layer → pipeline DAG → effects/meters → output device / virtual device / recorder encoder. The UI only configures and monitors this path; it does not process audio itself.
14. Cross-cutting concerns
A few modules cut across the whole app: audio/volume controls device volume, audio/permission handles platform permission checks, audio/resample and audio/clock keep streams aligned, and the error/updater/app_info modules provide app-wide UX support. These are secondary to the audio graph but important for completeness.
Main entry points: pipeline Pipeline DAG · routes App routes · audio Platform backends · commands.rs Commands
Components 21
Svelte UI
Presentation layer for editing, monitoring, and app UX.
- App routes · Top-level pages for the main editor, pipeline detail, preview, and virtual-device management.
src/routes - Flow editor · Visual node editor with inputs, effects, outputs, undo/redo, and snapshot history.
src/lib/modules/flow - Pipeline model · Frontend pipeline state and generated Rust-backed types shared with the backend.
src/lib/modules/pipeline - Audio UI · Frontend audio status, activation, runtime controls, and device-related UI.
src/lib/modules/audio - Overlays · Reusable modal, menu, tooltip, context, and popover infrastructure.
src/lib/modules/overlay - Updater · Update notifications and related frontend state/methods.
src/lib/modules/updater - Error UX · Frontend error initialization, state, and modal presentation.
src/lib/modules/error
Tauri Rust
Runtime backend for commands, audio engine, and OS integration.
- Tauri app · App entrypoints and bootstrap for the desktop shell.
src-tauri/src/main.rs - App state · Shared backend state stored for commands and engine coordination.
src-tauri/src/state.rs - Commands · Callable operations exposed from Rust to the frontend.
src-tauri/src/commands.rs - Audio engine · Core Rust runtime that owns routing, scheduling, and stream execution.
src-tauri/src/audio/engine.rs - Pipeline DAG · Graph execution, signal representation, worker execution, meters, and file reading.
src-tauri/src/audio/pipeline - Capture · System, per-app, file, and device input acquisition across platforms.
src-tauri/src/audio/capture - Device I/O · Mic/speaker enumeration and playback/device plumbing.
src-tauri/src/audio/device - System audio · OS-specific loopback and system-audio capture integration.
src-tauri/src/audio/system_audio - Virtual device · OS-specific virtual-device support for routing audio back into the system.
src-tauri/src/audio/virtual_device - DSP effects · Gain, mute, EQ, compressor, delay, limiter, gating, reverb, saturator, and analysis modules.
src-tauri/src/audio/effects - Encoders · Format-specific writers for recording and exported audio files.
src-tauri/src/audio/encoders - Platform backends · macOS, Linux, and Windows-specific implementation modules for capture, output, volume, and permissions.
src-tauri/src/audio
Native support
macOS-only Swift/C++ bridge and driver support.
- Native support · macOS bridging code and the system virtual-driver implementation.
src-tauri/native
Packaging
Build, capability, and release integration.
- Build & packaging · Build script, Tauri configs, capabilities, and release workflows.
src-tauri/build.rs
Connections 28
- App routes → Flow editor: renders · Main editor routes host the flow editor and related pages.
- App routes → Audio UI: shows · Routes include audio status and control surfaces.
- App routes → Overlays: uses · Pages rely on overlay primitives for dialogs and menus.
- App routes → Updater: shows · App routes surface update prompts and banners.
- App routes → Error UX: shows · Routes present global error UI.
- Flow editor → Pipeline model: binds · The editor consumes the typed pipeline model and generated node data.
- Flow editor → Commands: calls · Editor actions are persisted and executed through backend commands.
- Audio UI → Commands: calls · Audio controls drive backend actions via Tauri commands.
- Error UX → Commands: listens to · Error state is populated from backend command failures.
- Tauri app → App state: initializes · App bootstrap creates shared runtime state.
- Tauri app → Commands: registers · Startup wires commands into the shell.
- Commands → Audio engine: controls · Commands steer the engine and expose audio operations.
- Audio engine → Pipeline DAG: runs · Engine execution is centered on the pipeline DAG and workers.
- Pipeline DAG → Capture: ingests · The graph consumes audio from capture sources.
- Pipeline DAG → Device I/O: plays to · Processed audio is delivered to device outputs.
- Pipeline DAG → System audio: captures · System audio feeds into the pipeline through platform-specific sources.
- Pipeline DAG → Virtual device: routes to · The graph can terminate in virtual-device outputs.
- Pipeline DAG → DSP effects: applies · DSP modules are applied inside the pipeline.
- Pipeline DAG → Encoders: records via · Recording outputs are encoded by format writers.
- Platform backends → Capture: implements · Platform modules specialize source capture and device access.
- Platform backends → Device I/O: implements · Platform modules provide device enumeration and playback backends.
- Platform backends → System audio: implements · OS-specific system-audio capture is selected per platform.
- Platform backends → Virtual device: implements · Virtual-device support varies by platform.
- Platform backends → Encoders: supports · Platform code may contribute to codec and audio I/O support.
- Native support → System audio: bridges · macOS native code bridges ScreenCaptureKit and related APIs.
- Native support → Virtual device: drives · Native support includes the macOS audio driver for virtual devices.
- Build & packaging → Tauri app: packages · Build and release tooling assemble the desktop shell.
- Build & packaging → Native support: compiles · Build scripts coordinate Swift and C++ native pieces.