Skip to main content

songbird-export

Offline audio rendering — master export, stem export, track bounce, and .bird-file rendering. This crate renders audio from the engine graph to WAV files without real-time constraints. It processes the entire timeline (or a time range) as fast as possible and writes the result to disk.

Module Map

songbird-export/src/
├── lib.rs          — ExportConfig, StemMode, write_wav, export_master, export_stem, export_all_stems, trim_silence_file
├── render.rs       — internal offline render loop (graph.process in a tight loop)
├── bounce.rs       — BounceConfig, bounce_track, FreezeManager, FrozenTrack
└── bird_render.rs  — Render a `.bird` source string end-to-end (used by songbird-cli)

Public API (top-level functions)

  • export_master(path, &mut graph, &mut transport, &ExportConfig, progress) — full mixdown to a stereo WAV.
  • export_stem(path, &mut graph, &mut transport, &StemExportConfig, progress) — solo a node, render to WAV, restore solo.
  • export_all_stems(output_dir, &mut graph, &mut transport, &ExportConfig, &[NodeId], StemMode) — one WAV per node.
  • bounce::bounce_track(&mut graph, &mut transport, NodeId, name, &BounceConfig, progress) — per-track bounce, optional normalization.
  • trim_silence_file(input, output, threshold) — post-process trim of an existing WAV.
  • bird_render::render_bird_to_wav(&source, output_str, &BirdRenderConfig, progress) — full session build + render from .bird text.
  • write_wav / write_wav_dithered — TPDF dither when reducing to 16/24-bit; bypass for 32-bit float.

How it’s wired

The sync engine calls into this crate via EngineBackend methods on AppState:
Sync commandBackend methodRenders via
export.masterexport_master_mixexport_master
export.master_with_laneexport_master_with_laneexport_master (with swap_audition_lanes first)
export.stemexport_stemexport_stem
export.all_stemsexport_stemsexport_stem per track
export.bounce_trackbounce_trackbounce_track
Progress and completion are emitted on the notifications channel (notifications:export_progress, notifications:export_done).

Known limitation: take-lane filtering during offline export

The two render entry points work differently:
  • bird_render::render_bird_to_wav runs the full pipeline — session.scheduler.schedule(...) then session.graph.process_with_clips(...) — so clips on the timeline are dispatched correctly. This is the path songbird-cli render uses.
  • export_master (used by all export.* channel commands today) calls graph.process directly without driving the scheduler. It only renders signals already flowing through the live graph (running synths, monitored input).
Because the offline export does not currently invoke the scheduler, the per-track audition state set by controller.swap_audition_lanes(...) has no effect on the rendered file today. export.master_with_lane is fully wired (snapshot, swap, restore), produces a uniquely-named output file, and is correct on the IPC seam — but the audio inside that file is the same as export.master until the offline export gains scheduler integration. When the offline export path is upgraded to drive the scheduler, lane variations and stem-from-clips will start producing distinct content with no API changes.

Tests

cargo test -p songbird-export
Tests use deterministic output verification (RMS, peak, fingerprints) against synthesised graphs — no audio hardware required.