wiki
Miscellaneous

flaccheck

What flaccheck is, why we built it, how detection works, and how we validated it against other tools.

flaccheck is an open-source Rust CLI (plus local web UI) that answers one question: is this “lossless” file actually lossless, or a lossy transcode in disguise?

It scans FLAC, ALAC, WAV, AIFF, and other decodable formats locally — no cloud upload — and returns a structured verdict with optional per-detector evidence.

The one-sentence mental model

flaccheck does not trust file extensions or tags. It decodes audio to PCM and looks for lossy codec fingerprints in the spectrum and time domain.

Public repo: github.com/dasunNimantha/flaccheck

What it is

PieceRole
CLI (flaccheck scan)Batch-scan files or directories; JSON/CSV/HTML/text output
Web UI (flaccheck serve)Drag-and-drop analysis on 127.0.0.1
Detector libraryReusable Rust crates for spectral, MDCT, artifact, and hi-res checks
Optional ML tierONNX borderline classifier for ambiguous cases (--ml)

Why we built it

Fake lossless is common in downloaded music libraries:

  • A 128 kbps MP3 re-wrapped as FLAC does not recover quality — it only grows file size.
  • “Hi-res” 24-bit releases are sometimes upsampled 16-bit PCM with no new information.
  • Marketplaces and forum rips are not always honest about source format.

Manual tools like Spek show spectrograms but do not scale to whole libraries. Existing automated tools either false-positive on genuine masters (flagging narrow-band archival transfers) or miss transcodes on some codecs.

We wanted a tool that:

  1. Runs fully offline on Linux/macOS/Windows
  2. Abstains (INCONCLUSIVE) on ambiguous band-limited content instead of guessing
  3. Ships with reproducible benchmarks against alternatives (FLAC Detective, isflac, soundaudit, audiocheckr)

How detection works

Detector tiers

TierMethodWhat it catches
1Spectral cutoff & brick-wall fingerprintMP3/AAC/Opus frequency cliffs
2MDCT quantization residualLossy codec block structure
3Pre-echo, phase, joint-stereo artifactsMP3/AAC encoder signatures
4Fake hi-res16-bit content in 24-bit containers
5Abstention78 rpm transfers, AM radio, narrow masters

Evidence from all tiers is fused into one transcode verdict and a confidence score. Use --explain to see per-detector notes in the report.

Technical pipeline

1. Decode to PCM

Every file is decoded to interleaved f32 PCM — tags and container format are ignored after decode.

PathWhen used
symphoniaFLAC, WAV, AIFF, ALAC, AAC, MP3, Vorbis, .m4a
ffmpeg pipeAPE, WavPack, Opus (when ffmpeg is in PATH)

The decoder picks the first audio track, preserves sample rate and channel count, and hands a PcmBuffer to the detector pipeline.

2. Windowed analysis

Long tracks are not analyzed as one giant FFT. The PCM is split into time windows (configurable duration and count). Windows with RMS below 15% of the peak are dropped so silent gaps do not dilute the spectrum.

3. Tier 1 — Spectral (rustfft, 4096-point)

On each window:

  1. Convert to mono (left channel)
  2. Compute average power spectral density across windows
  3. Smooth the PSD in dB (5-bin moving average)
  4. Measure:
    • Brick-wall cutoff — sharp drop to a digital noise floor below Nyquist
    • Rolloff steepness — dB/octave at the cliff (MP3 tends to be steeper than AAC)
    • Spectral edge — highest frequency with meaningful energy
    • AAC shelf — gradual high-frequency shelf before cutoff
    • SBR mirroring — HF band that mirrors energy from a lower band (HE-AAC hint)

Codec signature matching compares measured cutoff/edge against known MP3, AAC, and Opus bitrate tables (e.g. MP3 128k ≈ 16 kHz, AAC 256k ≈ 20 kHz). A match raises codec_guess and codec_certainty.

full_band is set when content reaches ~97% of Nyquist and there is no strong brick wall — a key input to abstention logic.

4. Tier 2 — MDCT / PQMF quantization

Searches for lossy codec block structure in the decoded samples:

  • MP3 PQMF / granule hybrid filterbank patterns
  • MDCT quantization residual from transform-codec frame boundaries

This tier is gated by scan mode and spectral suspicion — it is skipped on clean full-band files in balanced mode because PQMF heuristics false-positive on live/acoustic material. Quant evidence can corroborate a spectral cutoff but never alone flag full-bandwidth audio as transcoded.

5. Tier 3 — Time-domain artifacts

Looks for encoder-specific signatures in the waveform:

SignalWhat it detects
Pre-echoSmear before transients (MDCT pre-echo)
Phase discontinuityFrame-boundary phase jumps
Joint stereoMid/side correlation patterns
Noise floorDigital silence above the cutoff frequency

fast mode runs a light artifact pass; balanced / max run the full set when spectral suspicion is elevated.

6. Tier 4 — Fake hi-res

Separate from transcode detection:

  • Upsampled — 16 kHz / 44.1 kHz content in a 48 kHz / 96 kHz container
  • Padded depth — 16-bit samples zero-padded into 24-bit words

A genuine transcode verdict can be downgraded to SUSPICIOUS if hi-res fraud is detected.

7. Evidence fusion & abstention

Each detector emits weighted evidence records (signal, value, weight, note). fuse_evidence() in flaccheck-core combines them:

weighted_score = Σ (value × weight) / Σ weight

Key rules:

  • Strong cliff (brick_wall ≥ threshold) → transcode fingerprint even on bass-heavy tracks with little HF energy
  • Strong AAC shelf + cutoff below Nyquist → transcode even without MP3-style brick wall
  • Band-limited content (edge below ~18 kHz, not full-band) → INCONCLUSIVE unless a strong cliff overrides
  • Full-band + low artifact suspicion → quant tier cannot promote to TRANSCODED on its own

Optional ML tier (--ml, ONNX): refines borderline cases only; does not replace the rule-based fusion.

Scan modes

ModeSpectralQuantArtifacts
fastskiplight
balanced (default)coarse on suspectsfull on suspects
maxexhaustivefull always

Verdicts

VerdictMeaning
GENUINENo lossy fingerprint detected in decoded PCM
TRANSCODEDStrong evidence of lossy→lossless transcode
SUSPICIOUSSome lossy indicators; not conclusive
INCONCLUSIVEBand-limited or ambiguous — tool refuses to guess

GENUINE ≠ provenance

GENUINE means no lossy encoding fingerprint, not “ripped from original CD.” A native AAC file analyzed for transcode fingerprints is a different question than “is the container ALAC?” — see below.

ALAC and .m4a files

flaccheck can scan .m4a and .alac files (decoded via symphonia). Two questions often get conflated:

QuestionTool
What codec is in the container? (ALAC vs AAC)ffprobe -show_entries stream=codec_name
Was lossy audio re-encoded as fake lossless?flaccheck scan

Example: a streaming AAC .m4a is legitimately lossy — not “fake ALAC.” flaccheck analyzes the audio content, not the shopping label.

Quick usage

git clone https://github.com/dasunNimantha/flaccheck.git
cd flaccheck
cargo build --release -p flaccheck

./target/release/flaccheck scan ~/Music --format json --explain
./target/release/flaccheck serve   # local web UI

Requirements: Rust stable. Optional ffmpeg for APE, WavPack, and Opus decode.

Native decode: FLAC, WAV, AIFF, ALAC, AAC, MP3, Vorbis, .m4a · With ffmpeg: APE, WavPack, Opus

What we optimized for

Precision on genuine masters

Do not call real lossless sources fake. flaccheck abstains on narrow-band content rather than marking 78 rpm transfers as transcodes.

Recall on obvious transcodes

MP3→FLAC is the easy case (~98% recall on combined corpora). High-bitrate AAC and MP3 V0 are intentionally harder.

Reproducibility

Labeled ffmpeg transcode corpora, comparison scripts, and chart JSON in the repo — not hand-waved blog numbers.

Benchmarks & validation

We validate flaccheck against labeled real-music corpora — not synthetic sine waves — by transcoding genuine sources with ffmpeg and comparing tool outputs to ground truth.

Charts and raw JSON: docs/benchmarks/comparison.json

Why benchmark this way

ApproachProblem
Synthetic sine/noise onlyNo brick walls, no real encoder signatures
Trust vendor claims“100% accurate” with no corpus
Single album hand-testNot reproducible

Our approach:

  1. Start from genuine lossless sources (archival, classical, live, netlabel)
  2. Transcode with ffmpeg to MP3/AAC/Opus/Vorbis, wrap back to FLAC
  3. Label each file genuine or transcoded in manifest.json
  4. Run flaccheck and competitors on identical paths
  5. Score precision, recall, and false positives on genuine references

Recall definition

A transcode counted as a miss if the tool says INCONCLUSIVE or GENUINE. flaccheck deliberately abstains on band-limited files — those count against recall but protect precision.

Corpora

CorpusFilesGenuineTranscodesNotes
v1 (realistic)12111110Archival/classical/live sources via generate_realistic.sh
v2 (validation)13212120Independent etree/netlabel sources via download_benchmark_v2.sh
Combined25323230benchmark_compare.py --combine

Tools compared

ToolVersion
flaccheck0.1.x balanced
FLAC Detective1.7
isflac0.1.4
soundaudit0.1.2
audiocheckr0.3.7

Combined results (253 files)

ToolPrecisionRecallFalse positives on genuine
flaccheck99%85%1 / 23
audiocheckr93%82%15 / 23
isflac95%57%7 / 23
FLAC Detective97%47%4 / 23
soundaudit0%0%

flaccheck leads on precision (one false positive across 23 genuine references). audiocheckr catches more borderline transcodes but flags most genuine files as fake.

Recall by codec (flaccheck)

CodecRecall
MP398%
AAC55%
Opus98%
Vorbis85%

AAC at 128–256 kbps is the hard case — gentle shelf instead of a hard brick wall.

Reproduce benchmarks

Build corpora:

./datasets/generate_realistic.sh /path/to/sources datasets/output/realistic
./datasets/download_benchmark_v2.sh
./datasets/generate_realistic.sh datasets/benchmark_v2_sources datasets/output/benchmark_v2

Run scanners per corpus:

cargo build --release -p flaccheck
./target/release/flaccheck scan datasets/output/realistic \
  --format json --quiet -o benchmarks/flaccheck_per_file.json --workers 8
flac-detective --format json --output benchmarks/flac_detective.json datasets/output/realistic

Compare and merge:

python3 scripts/benchmark_compare.py --collect   # per corpus
python3 scripts/benchmark_compare.py --combine   # → docs/benchmarks/

Research references

Detection draws on published work on lossy fingerprinting: D'Alessandro & Shi (ACM MM&Sec 2009), Derrien (JAES 2019), Lacroix et al. (AES 2015).

On this page