audiofp
Audio fingerprinting library for Rust with classical landmark and band-power algorithms, in-memory matching, streaming extraction, file decoding, and AudioSeal-compatible watermark detection.
Overview
audiofp provides three complementary classical fingerprinters for music identification, each with offline and streaming variants, plus an in-memory matching layer for identification:
| Method | Use Case | Sample Rate | Frame Rate | Output Size |
|---|---|---|---|---|
| Wang | Music ID, Shazam-style matching | 8 kHz | 62.5 fps | ~2.4 KB/s (fan-out 10) |
| Panako | Music ID with ±5 % tempo robustness | 8 kHz | 62.5 fps | ~2.0 KB/s (fan-out 5) |
| Haitsma | Compact dense IDs, fastest extraction | 5 kHz | 78.125 fps | 312 B/s |
| Matching | In-memory ID (WangMatcher, HaitsmaMatcher, …) |
— | — | — |
| Streaming | Real-time hash emission | (per algorithm) | (per algorithm) | Bit-exact offline parity |
| Watermark | AudioSeal detection (BYO ONNX) | 16 kHz | (per model) | Detection + 16-bit message |
Perfect for:
- Music identification ("what is this song?")
- Audio deduplication at scale
- Royalty / rights enforcement against re-encoded content
- Embedding-based similarity search and cover/remix detection (BYO ONNX model via the
neuralfeature) - Watermark verification on generative-AI audio
Features
- Three Classical Algorithms - Wang (landmark pairs) + Panako (triplet hashes with tempo β) + Haitsma–Kalker (32-bit/frame band sign)
- In-Memory Matching -
WangMatcher/HaitsmaMatcher/PanakoMatcher(tempo-invariant 2-D Hough + RANSAC) /NeuralMatcherplusmatch_best/match_rankedand transientWangIndex/HaitsmaIndex/PanakoIndexaccelerators for 1:N identification. No persistence or DB adapters. - Truly Incremental Streaming - Per-push CPU proportional to new samples, not total stream length. Rolling spectrogram + per-bucket finalisation + per-anchor target accumulator. Bit-exact parity with offline
extract(verified by the test suite at every chunk size). - Bit-Exact Determinism - Same input always produces the same hashes; verified down to 1-sample-per-push streaming chunks
bytemuck::PodHash Types - Persist hashes directly to mmap'd files or ship over a C ABI without serialization- Audio File Decoding - MP3, FLAC, WAV, OGG-Vorbis, AAC-in-MP4, raw PCM via Symphonia
- High-Quality Resampling - Built-in windowed-sinc Kaiser resampler with auto anti-aliasing cutoff
- Watermark Detection - AudioSeal-compatible ONNX wrapper (Tract backend); typed model is cached per input length and rebuilt automatically when the length changes
- Neural Embedder - Generic ONNX log-mel embedder with offline + streaming modes; build-once-runnable, zero-alloc
try_push_withcallback (scratch is allocated at construction, reused on every push) - DSP Primitives Reusable - Public
dsp::stft,dsp::mel,dsp::peaks,dsp::resample,dsp::windows - Allocation-Free Hot Path - Streaming
pushreuses pre-allocated scratch after warmup no_std + allocCapable - DSP and classical fingerprinters compile without std (host-only today; bare-metal in roadmap)- Feature-Gated Heavy Deps - Symphonia and Tract both opt-in via Cargo features
- Optional
mimalloc- Single-flag opt-in to installmimallocas the global allocator
Installation
[]
# WAV + MP3 decoding for the quick-start below (pick the codecs you need):
= { = "0.4", = ["std-wav", "std-mp3"] }
The default build is no_std + alloc with no codecs. Decoding helpers
(audiofp::io) are opt-in per codec: std-wav, std-mp3, std-flac,
std-ogg, std-aac, std-mp4, plus std-aiff / std-mkv / std-adpcm /
std-alac for the extended formats — or all-codecs for every codec at
once (the pre-0.4.0 std behavior).
Feature Flags
| Feature | Default | Description |
|---|---|---|
std-wav |
No | WAV + raw PCM decoding via Symphonia (audiofp::io) |
std-mp3 |
No | MP3 decoding via Symphonia |
std-flac |
No | FLAC decoding via Symphonia |
std-ogg |
No | Ogg-Vorbis decoding via Symphonia |
std-aac |
No | AAC decoding via Symphonia |
std-mp4 |
No | AAC-in-MP4 / ISO-BMFF decoding via Symphonia |
std-aiff / std-mkv / std-adpcm / std-alac |
No | Extended codecs |
all-codecs |
No | Every codec at once — the pre-0.4.0 std behavior |
rayon |
No | Parallel batch fingerprinting via fingerprint_batch_parallel (implies std) |
watermark |
No | Enables audiofp::watermark via Tract ONNX runtime (implies std) |
neural |
No | Enables audiofp::neural: generic ONNX log-mel embedder via Tract (BYO model; implies std) |
mimalloc |
No | Installs mimalloc::MiMalloc as the process-wide #[global_allocator] (implies std) |
Minimal build (no_std + alloc, DSP and classical only):
[]
= { = "0.4", = false }
Quick Start
Fingerprint a file
use Wang;
use decode_to_mono_at;
use ;
Match two fingerprints (Wang)
use Wang;
use decode_to_mono_at;
use ;
use ;
Streaming Mode
use StreamingFingerprinter;
use StreamingWang;
use PI;
On a realtime audio thread, bound on ZeroAllocStreaming instead and
use the callback variants — after warmup they allocate nothing:
use ;
use StreamingWang;
StreamingWang, StreamingPanako, and StreamingHaitsma all carry the
bound (pinned by a counting-allocator test: zero allocs across 40 pushes
plus flush after warmup). The neural streamer opts out (Frame = Vec<f32>
allocates by design) — its inherent try_push_with is the zero-alloc path.
Documentation
For complete API reference and usage examples, see USAGE.md.
Performance
Offline extract (cargo bench --bench extract, 30 s of synthetic audio):
| Algorithm | 30 s of audio | Realtime factor |
|---|---|---|
Wang |
79 ms | 380× |
Panako |
81 ms | 370× |
Haitsma |
42 ms | 714× |
Streaming push (cargo bench --bench streaming, 10 s of synthetic audio):
| Streaming type | Small chunks (256 samples) | Large chunks (1 s) | latency_ms() |
|---|---|---|---|
StreamingWang |
10.5 ms | 10.6 ms | 2 256 ms |
StreamingPanako |
11.6 ms | 11.4 ms | 2 784 ms |
StreamingHaitsma |
6.3 ms | 6.7 ms | 409 ms |
Neural front-end (cargo bench --features neural --bench neural_frontend):
| Path | Time |
|---|---|
log_mel_pipeline_1s_window |
297 µs |
strided_tensor_write |
7.6 µs |
l2_normalize_1024d |
2.5 µs |
Matching (cargo bench --bench matching, 5 s synthetic fingerprints):
| Path | Time | Notes |
|---|---|---|
WangMatcher 1:1 self-match |
~111 µs | Offset-histogram voting + prominence |
HaitsmaMatcher 1:1 exact |
~18 µs | Exhaustive BER at best alignment |
PanakoMatcher 1:1 |
~264 µs | 2-D Hough + RANSAC line-fitting |
WangIndex N=100 query |
~102 µs | Inverted index + sliding-window peak |
Latency budget (per query, default configs, Intel i5-1135G7):
| Catalog size | WangIndex query |
Throughput |
|---|---|---|
| 100 tracks | ~102 µs | ~9 800 q/s |
| 1 000 tracks | ~1 ms (est.) | ~1 000 q/s |
| 10 000 tracks | ~10 ms (est.) | ~100 q/s |
Index query scales approximately linearly with catalog size (one candidate-scoring pass per reference with hash hits). For catalogs above ~10 000 tracks, use
min_votes/min_scorepre-filters or shard the index.
Run benchmarks for your own host:
Robustness
-
Codec-tolerant by design — Wang and Panako are spectral-peak based; Haitsma is band-power-difference based. All three survive lossy re-encoding, verified by the test suite on real music:
Codec Wang (Jaccard) Panako (Jaccard) Haitsma (bit-sim) WAV/FLAC (lossless) 1.000 — 1.000 MP3 128 kbps 0.40 0.45 0.93 OGG-Vorbis 0.36 0.42 0.91 AAC (M4A) 0.50 0.54 0.77 AIFF (lossless) 1.000 — — Cross-track (different song) 0.001 — — Test audio: "Galway" and "Furious Freak" by Kevin MacLeod, 16 s each, 6 codec variants. Thresholds: Wang ≥ 0.25, Panako ≥ 0.20, Haitsma ≥ 0.75. In practice, 5–10 matching hashes suffice for confident identification.
-
Two-track discrimination verified — different songs produce <0.1% hash overlap (random collision floor), while the same song across codecs produces 25–80% overlap.
-
606 tests including adversarial stress tests, real-audio E2E across 6 codecs, and property-based streaming/offline parity checks. See ROBUSTNESS.md for full methodology.
Comparison with Alternatives
| Feature | audiofp | chromaprint-rust | dejavu (Python) |
|---|---|---|---|
| Pure Rust | Yes | No (FFI to C lib) | No |
| Wang landmarks | Yes | No | Yes |
| Panako triplets (tempo-robust) | Yes | No | No |
| Haitsma–Kalker | Yes | No | No |
| Streaming variants | Yes | Limited | No |
| Bit-exact streaming/offline parity | Yes | No | N/A |
| File decoding included | Yes (Symphonia) | Yes (limited) | Yes (FFmpeg) |
| Watermark detection | Yes (AudioSeal) | No | No |
no_std + alloc capable |
Yes (host) | No | N/A |
bytemuck::Pod hash types |
Yes | No | N/A |
| Built-in resampler | Yes | No | No |
| In-memory matcher (Wang/Haitsma) | Yes | No | Yes (Dejavu) |
Measured head-to-head on a shared corpus (overlap, 1:N identification, latency): BENCHMARKS.md.
Security
See SECURITY.md for the threat model (audio / PCM / ONNX / hash outputs) and how to report vulnerabilities privately. Fingerprints are perceptual, not cryptographic MACs — use DecodeLimits with decode_to_mono_limited for untrusted uploads.
Contributing
See CONTRIBUTING.md for guidelines. Quick start:
&&
CI runs fmt, clippy, and test on ubuntu/macOS/Windows on every push and PR.
License
MIT License — see LICENSE for details.
References
- Avery Wang, An Industrial-Strength Audio Search Algorithm (ISMIR 2003) — Wang landmarks
- Joren Six & Marc Leman, Panako: A Scalable Acoustic Fingerprinting System (ISMIR 2014); 2021 update — triplet β hash
- Jaap Haitsma & Ton Kalker, A Highly Robust Audio Fingerprinting System (ISMIR 2002) — band-power sign bits
- San Roman, R., Fernandez, P., Elsahar, H., Défossez, A., Furon, T. & Tran, T. Proactive Detection of Voice Cloning with Localized Watermarking. arXiv:2401.17264, 2024 (AudioSeal) — watermark model. https://arxiv.org/abs/2401.17264