# 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:
```toml
[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:
```powershell
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg install soxr:x64-windows-static-md
```
On MSYS2:
```bash
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
```rust
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`.
```bash
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.
```bash
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.
| 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.
| 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
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
<http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or
<http://opensource.org/licenses/MIT>)
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](NOTICE) for details.