audio-engine-core 0.1.0

Reusable decoder, DSP, loudness, resampling, and streaming pipeline primitives
Documentation

audio-engine-core

Reusable decoder, DSP, loudness, resampling, and streaming pipeline primitives extracted from the Lyne audio engine.

This crate is the app-agnostic core layer. It is intended for experiments and integration work around high-quality local audio processing, not as a stable 1.0 SDK yet. The public API is versioned as 0.1.x and may change while the larger player continues to evolve.

What Is Included

  • Streaming decode helpers built on Symphonia.
  • SoX VHQ resampling wrappers and streaming resampler utilities.
  • DSP processors such as EQ, crossfeed, saturation, FFT convolution, dynamic loudness, volume smoothing, noise shaping, and spectrum analysis.
  • EBU R128 loudness and true-peak measurement helpers.
  • Lock-free DSP parameter snapshots and processor adapters for realtime audio callback integration.
  • A small streaming pipeline/ring-buffer primitive.

What Is Not Included

  • Audio device ownership or CPAL/WASAPI output stream management.
  • HTTP/WebSocket server routes.
  • Desktop UI, Tauri integration, media-library scanning, playback queue logic, WebDAV, NetEase integration, or application runtime directories.
  • A stable compatibility layer for every internal Lyne use case.

Those layers remain in the root Lyne application crate.

Cargo Features

Both features below are enabled by default. Disable them with default-features = false to drop the corresponding dependency.

  • http (default): HTTP/HTTPS streaming decode via reqwest, including Range streaming and full-download fallback. With this off, StreamingDecoder only opens local files; passing an http(s):// path returns a decoder error, and the reqwest dependency and NetworkError type are not compiled.
  • loudness-db (default): SQLite-backed loudness metadata persistence (LoudnessDatabase, TrackLoudness, DatabaseStats) via rusqlite. With this off, the EBU R128 measurement helpers (LoudnessMeter, LoudnessNormalizer, TruePeakDetector) still work; only the on-disk cache is removed.

DSP-only consumers can take a much smaller dependency tree:

[dependencies]
audio-engine-core = { version = "0.1", default-features = false }

Native Dependency: SoXR

The resampler depends on soxr, which requires the SoXR native library during build/link.

On Windows, vcpkg is the recommended path:

git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg install soxr:x64-windows-static-md

On MSYS2:

pacman -S mingw-w64-x86_64-soxr

On Unix-like systems, install SoXR through your system package manager and make sure pkg-config can locate it.

Quick Example

use audio_engine_core::{LoudnessMeter, StreamingDecoder};

fn analyze_file(path: &str) -> Result<f64, Box<dyn std::error::Error>> {
    let mut decoder = StreamingDecoder::open(path)?;
    let mut meter = LoudnessMeter::new(decoder.info.channels, decoder.info.sample_rate);

    while let Some(samples) = decoder.decode_next()? {
        meter.process(&samples);
    }

    Ok(meter.integrated_loudness())
}

Runnable Examples

The examples/ directory contains self-contained programs that need no audio files and no optional features:

  • resample_sine — streams a synthetic 48 kHz sine through the SoX VHQ resampler down to 44.1 kHz, demonstrating the chunked feed-then-flush pattern.
  • equalizer_curve — runs a stereo buffer through the 10-band Equalizer.
cargo run --example resample_sine
cargo run --example equalizer_curve

Realtime Notes

The crate exposes lock-free parameter containers and processor adapters used by Lyne's realtime callback path. Keep allocations, locks, file I/O, logging, and network I/O out of an audio callback. Allocate and configure processors before entering the realtime path, then update parameters through the provided atomic snapshot types.

Performance And Audio Quality

These numbers come from the benchmarks in benches/, which run entirely against this crate's public API. They are evidence for one machine and one configuration, not a universal claim. Reproduce them with cargo bench; the exact values will differ by CPU, compiler version, and load.

cargo bench --bench audio_callback_chain_perf -- --quick
cargo bench --bench audio_resampler_streaming_perf -- --quick
cargo bench --bench audio_convolver_perf -- --quick
cargo bench --bench audio_lockfree_params_perf -- --quick
cargo bench --bench audio_fir_eq_perf -- --quick
cargo bench --bench audio_quality_measurements -- --quick

Drop --quick for the longer multi-trial runs the numbers below were taken from.

Realtime processing budget

Per-sample/per-buffer cost of the DSP and resampler paths at a 512-frame buffer. These exclude the decoder and the OS audio device write; they measure only the in-crate processing.

Path Per sample Per 512-frame buffer Bench
DSP chain, no convolver (EQ, saturation, crossfeed, convolver slot empty, volume, dynamic loudness, peak limiter) 18.4 ns 18.8 us audio_callback_chain_perf
DSP chain with convolver 27.8 ns 28.5 us audio_callback_chain_perf
Streaming resampler, 44.1 kHz to 48 kHz 7.9 ns/input sample 8.1 us/input buffer audio_resampler_streaming_perf
FFTConvolver alone, 256-tap IR, stereo ~10 ns n/a audio_convolver_perf
FIR EQ apply, 511-tap IR via FFTConvolver, stereo 9.6 ns 9.8 us audio_fir_eq_perf

For a 512-frame buffer at 48 kHz (about 10.7 ms of audio), even the heaviest chain measured here uses well under one callback period.

Lock-free parameter reads

The atomic parameter snapshots (AtomicEqParams, AtomicVolumeParams, and the rest) are the mechanism for pushing parameter changes into the audio callback without locks. Reading the full set of cached parameters once per callback costs about 7 ns with the generation-based snapshot path, versus ~50 ns for a naive split-atomic field-by-field read and ~83 ns for an unconditional ArcSwap guard load — an ~86% to ~92% improvement (audio_lockfree_params_perf).

FIR EQ IR generation

FirEq designs a linear- or minimum-phase impulse response from 10 band gains; the IR is then convolved (typically with FFTConvolver) to apply the EQ. Generation is an offline/control-thread cost, not a per-sample one. On this machine a 511-tap linear-phase design regenerates in ~31 us; minimum-phase designs cost roughly 3x more because of the extra cepstral phase shaping, and cost scales with tap count (audio_fir_eq_perf).

Objective audio-quality measurements

audio_quality_measurements generates synthetic f64 signals, runs them through this crate's processor modules, and analyzes the rendered buffers numerically. This is native-rendered-buffer evidence, not analog output capture: no audio device, OS mixer, DAC/ADC loopback, or microphone is involved, and it does not replace listening tests.

Metric Result
Resampler THD+N, 44.1 kHz to 48 kHz -187.0 dB
Passband max deviation, 20 Hz to 18 kHz 0.0013 dB
20 kHz resampler gain -0.0062 dB
Worst fitted alias attenuation, 96 kHz to 48 kHz -294.7 dB
Limiter output ceiling from a +5.11 dBFS transient -1.00 dBFS
Limiter below-threshold THD+N -238.3 dB
LoudnessMeter integrated parity vs direct ebur128 0.000000 LU

The noise shapers (NoiseShaper) redistribute quantization error spectrally rather than lowering broadband noise: the shaped curves strongly reduce the 2-6 kHz band while pushing energy into 14-18 kHz, for up to a +34.9 dB ear-band advantage over flat TPDF dither.

The benchmark also includes an optional EBU Tech 3341/3342 expected-value corpus check. It is skipped unless the libebur128/test reference vectors are present (they are not bundled with this crate); the deterministic LoudnessMeter parity fixtures above always run.

One known limitation, kept visible: the sample-peak/lookahead limiter is not an intersample-true-peak guarantee. The full output-chain true-peak probe is report-only, and on stressed material it can leave the worst true peak close to the limiter ceiling rather than below a strict -1 dBTP target.

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Native dependency licensing

This crate links the SoXR native library (libsoxr), which is distributed under the LGPL-2.1. The Rust source in this crate is MIT OR Apache-2.0, but binaries that statically link libsoxr carry LGPL-2.1 relinking obligations. See NOTICE for details.