Skip to main content

songbird-engine

Core audio engine — graph, transport, scheduling, automation, mixing, and IPC types. This is the largest crate in the workspace (~70K lines, 2,170 tests) and contains all the runtime logic for audio processing, MIDI routing, clip playback, and the type definitions shared between the engine and the Tauri IPC layer.
See also: ../../ARCHITECTURE.md for the full architecture reference and threading model.

Module Map

songbird-engine/src/
├── graph.rs               — AudioGraph DAG, AudioNode, Connection, topological sort, parallel processing
├── transport.rs           — Play/stop/record/loop/seek, metronome, sample-accurate advance
├── tempo_map.rs           — BPM ↔ seconds/beats conversion, tempo automation
├── clip_scheduler.rs      — Timeline clip playback (MIDI + audio), beat-based scheduling
├── clip_launcher.rs       — Session view: ClipSlot, Scene, LaunchQuantize, FollowAction
├── automation.rs          — AutomationLane, AutomationPoint, breakpoint envelopes
├── automation_curve.rs    — Bezier/spline interpolation for smooth automation curves
├── mixer.rs               — Mixer model: TrackType, sends, groups, bus routing
├── mixer_snapshot.rs      — Capture/recall full mixer state
├── audio_io.rs            — cpal AudioDevice abstraction
├── ring_buffer.rs         — Lock-free SPSC ring buffer for engine↔UI commands/events
├── engine_controller.rs   — EngineController (real-time) + OfflineEngineController (offline/testing)
├── project_loader.rs      — Bird→EngineSession loader (full pipeline orchestrator)
├── ipc_types.rs           — 87+ IPC response types (TransportInfo, TrackInfo, ExportResponse, ...)
├── event_bridge.rs        — Engine → UI event channel (metering, transport state pushes)
├── plugin_chain.rs        — Nested plugin chain (ChainNode: Plugin | Container)
├── plugin_host.rs         — Plugin hosting utilities (parameter caching, state management)
├── midi_router.rs         — MIDI event routing, filtering, velocity curves
├── midi_utils.rs          — MIDI utility functions (note names, frequency conversion)
├── midi_effects.rs        — MIDI effects (arpeggiator, chord, transpose, etc.)
├── midi_clock.rs          — MIDI clock sync (send/receive)
├── midi_device.rs         — MIDI device enumeration and management
├── midi_learn.rs          — MIDI learn (parameter ↔ CC mapping)
├── modulation.rs          — Modulation matrix (LFO → parameter routing)
├── sidechain.rs           — Sidechain routing (key input, detector)
├── pdc.rs                 — Plugin delay compensation
├── metering.rs            — Level metering (peak, RMS, LUFS)
├── audio_analysis.rs      — Spectrum analysis, FFT, frequency detection
├── audio_bus.rs           — Audio bus routing model
├── audio_file.rs          — Audio file loading/decoding
├── audio_quantize.rs      — Audio-to-grid quantization
├── time_stretch.rs        — Time stretching / pitch shifting
├── tempo_detection.rs     — BPM detection from audio
├── sample_rate_convert.rs — Sample rate conversion
├── normalization.rs       — Audio normalization (peak, LUFS)
├── crossfade.rs           — Crossfade curves (equal power, linear, S-curve)
├── fade_handle.rs         — Fade in/out handles on clips
├── bounce.rs              — Track bounce (render in place)
├── track_freeze.rs        — Track freeze/unfreeze
├── track_group.rs         — Track grouping (link volume, mute, solo)
├── track_template.rs      — Track template save/load
├── clip_effects.rs        — Per-clip effect chain
├── comping.rs             — Comp lane management (take recording)
├── surround.rs            — Surround/spatial audio routing
├── groove.rs              — Groove templates (swing, humanize)
├── macro_controls.rs      — Macro knob → multi-parameter mapping
├── controller_profile.rs  — Hardware controller profiles
├── input_monitor.rs       — Input monitoring (direct, software)
├── preset_browser.rs      — Preset browsing and search
├── warp_marker.rs         — Audio warp markers (like Ableton's warp)
├── arrangement_marker.rs  — Arrangement markers and regions
├── time_signature.rs      — Time signature model
├── thread_pool.rs         — Audio thread pool management
├── diagnostics.rs         — Engine diagnostics (CPU, buffer stats)
├── signal_router.rs       — Signal routing matrix
├── undo_redo.rs           — Engine-level undo/redo
├── send_return.rs         — Send/return routing (SendReturnRouter, RoutingResult)
├── send_return_automation.rs — Send/return gain automation
└── [test modules]         — 12+ test files (see below)

Core Types

AudioGraph

Connection-based directed acyclic graph with topological sort and parallel processing.
let mut graph = AudioGraph::new();
let node_a = graph.add_node("Synth");
let node_b = graph.add_node("Reverb");
graph.connect(Connection::new(node_a, node_b, 0, 0)); // port 0 → port 0
graph.rebuild_topology(); // Kahn's algorithm, caches levels + scratch buffers
graph.process(num_samples, sample_rate); // rayon parallel per level
Key properties:
  • Connection ports — each connection has from_port and to_port indices, enabling sidechain routing
  • LatencyHint — per-node hint (RealTime, Buffered, Offline) for future ASIO-Guard-style dual-path rendering
  • Parallel levels — nodes at the same topological level execute concurrently via rayon::scope
  • ScratchPool — pre-allocated per-node buffers, zero allocation during process()

Transport

let mut transport = Transport::new(44100.0);
transport.set_bpm(128.0);
transport.play();
let (start, end) = transport.advance(512); // returns consumed time range
transport.set_loop(true, 0.0, 4.0);        // loop 0-4 seconds
transport.set_metronome(true);              // enable click track

AutomationState

let mut auto = AutomationState::new();
let lane = auto.get_or_create_lane(0, 0, "volume");
lane.add_point(AutomationPoint::new(0.0, 0.5));     // beat 0 → 0.5
lane.add_point(AutomationPoint::new(4.0, 1.0));     // beat 4 → 1.0
let value = lane.value_at_beat(2.0);                  // interpolated: 0.75

IPC Types

87+ strongly-typed response structs for all Tauri IPC commands:
// All IPC responses use this wrapper
pub struct IpcResult<T: Serialize> {
    pub ok: bool,
    pub data: Option<T>,
    pub error: Option<String>,
}

// Example response types
pub struct TransportInfo { pub state: String, pub position: f64, pub bpm: f64, ... }
pub struct TrackInfo { pub id: usize, pub name: String, pub volume: f64, ... }
pub struct ExportResponse { pub path: String, pub duration: f64, pub format: String, ... }

Test Suites

FileTestsPurpose
engine_controller.rs179Offline rendering, callbacks, cross-crate integration, robustness hardening
project_loader.rs60Bird→EngineSession loading, routing, plugins, edge cases
e2e_tests.rs15Full engine pipeline tests
engine_e2e_tests.rs15End-to-end: transport → graph → clips → output
audio_output_tests.rs25Waveform correctness, golden output, DSP parity
ipc_roundtrip_tests.rs87Serialize/deserialize all IPC response types
ipc_workflow_tests.rs15Full user workflows through IPC layer
ipc_handler_coverage_tests.rs54All 202+ Tauri command handlers wired
edge_case_tests.rs25NaN, Inf, empty buffers, extreme values
stress_tests.rs15Concurrent mutations, MIDI floods, large graphs
perf_tests.rs15Graph throughput, parallel speedup, zero-alloc
rt_safety_tests.rs25Zero allocation in audio callback path
bird_engine_integration_tests.rsBird→engine integration tests
bird_enhancements_e2e_tests.rsBird format enhancements E2E
session_pipeline_e2e_tests.rsSession pipeline E2E tests
cargo test -p songbird-engine               # All engine tests
cargo test -p songbird-engine -- e2e        # E2E tests only
cargo test -p songbird-engine -- audio_output  # Audio verification only