User Guide

Complete guide to using FLAC Detective effectively.

Table of Contents

Basic Usage

Analyze a Directory

# Analyze current directory
flac-detective .

# Analyze specific folder
flac-detective /path/to/music

# Analyze with full path (Windows)
flac-detective "C:\Users\YourName\Music\FLAC"

Analyze a Single File

flac-detective /path/to/file.flac

Recursive Analysis

FLAC Detective automatically scans subdirectories:

Music/
├── Artist 1/
│   ├── Album A/
│   │   ├── 01 - Track.flac  ← Analyzed
│   │   └── 02 - Track.flac  ← Analyzed
│   └── Album B/
│       └── 01 - Track.flac  ← Analyzed
└── Artist 2/
    └── Album C/
        └── 01 - Track.flac  ← Analyzed

All .flac files are found and analyzed automatically.

Command-Line Options

Output Formats

# Default: Text report to console + file
flac-detective /music

# JSON output (for automation)
flac-detective /music --format json

# Save to specific file
flac-detective /music --output custom-report.txt

# JSON to file
flac-detective /music --format json --output results.json

# CSV — library triage: one row per file, ranked most-suspicious first
flac-detective /music --format csv --output triage.csv

# HTML — a visual report you double-click to open (spectrum plots for flagged files)
flac-detective /music --format html --output report.html

Four formats, four jobs:

--format

For

Notes

text (default)

reading

human-friendly report + console summary

json

automation

full result objects, parse with jq etc.

csv

triaging a whole library

one row per file, sorted by score (most suspicious first); open in any spreadsheet to sort/filter. Columns: rank, score, verdict, hires_verdict, filename, cutoff_freq_hz, sample_rate, bit_depth, reason, filepath

html

seeing the evidence

a single self-contained .html (no external assets) with a sortable/filterable triage table and an inline spectrum plot for every flagged file — the MP3 “cliff” is visible to the eye, with the detected cutoff marked. Plots are drawn for flagged files only; a file that isn’t natively readable simply shows no plot

When a scan finds suspicious files, the console summary also prints the top suspects ranked by score, so you immediately see what to check first.

Fake hi-res is a second verdict, on its own line. A file can be genuine lossless and still not be what its label says: CD audio upsampled to 96 or 192 kHz, or 16-bit audio padded into a 24-bit (or 32-bit) container. Since v2.2.0 the text report lists those too — in the default report as 🎚️ FAKE HI-RES under “FILES TO LOOK AT”, in --advanced as a “FAKE HI-RES FILES” table with the verdict (UPSAMPLED, PADDED_DEPTH, UPSAMPLED_AND_PADDED) and the reading behind it. The CSV carries it as hires_verdict, the GUI as its “Hi-res” column. It never changes the transcode verdict. 32-bit integer FLAC (FLAC 1.4+) is analysed too.

Analysis Options

# Verbose mode (show detailed rule execution)
flac-detective /music --verbose

# Shorter windows (15 seconds per window, faster; reads less of each file)
flac-detective /music --sample-duration 15

# The default, 30 seconds, is the reading every published figure was measured
# at. A longer sample is not more accurate: it reads different audio, and a
# verdict that changes with the number is sitting on a reading boundary.

# Deep mode: run the ML rule (CNN) on every file
flac-detective /music --deep

What a normal scan already does for AAC and Vorbis (since v1.20.0). Before it clears a file the quick rules found nothing on, a normal scan asks Rule 13, which reads the MDCT grid AAC and Vorbis encoders leave behind. On a bench of 33 loud CD tracks it catches 32 of 33 AAC 256 (ffmpeg) and 33 of 33 Vorbis q6 transcodes, for about 4 s more per file. Since v1.20.1 it also asks on files with a low cutoff, which is where a low-bitrate Vorbis encode lands (-q1: 31 of 33 caught without the ML extra, 33 with it). Since v2.1.0 it also reads Opus, Vorbis at every quality (-q10 included) and HE-AAC v2 in a normal scan (issue #12). It does not read Apple’s AAC encoder (the iTunes and Apple Music format) well, nor MP3 320 / VBR: those still need --deep. HE-AAC v1 at low bitrates (64 kbps) is mostly out of reach.

When to use --deep. A normal scan keeps things fast by skipping the ML rule (Rule 12, the CNN) on files the quick heuristic rules and Rule 13 clear. That’s the right default for the common case — but it’s also where a high-bitrate MP3 or Apple AAC transcode hides: those leave no heuristic trace, so they sail through as AUTHENTIC. --deep runs the CNN on every file; when it is highly confident a full-range file is a transcode, the verdict is lifted to WARNING (“worth checking”, never an outright “fake”). The price is speed — every file is decoded and run through the CNN, so a large library takes noticeably longer. Reach for it when you specifically suspect high-bitrate MP3 or Apple AAC sources, or for a thorough second pass on a collection a fast scan called clean. It does not help with band-limited recordings (early-music, 1920s, solo acoustic) — that’s a genuine signal limit no tool can cross.

--deep (the GUI’s “Deep scan” box) is not an on/off switch for the CNN. With the [ml] extra installed, Rule 12 runs on every file the fast rules leave in doubt, deep or not, so seeing a CNN line in a normal scan is expected. Deep only adds the files the fast rules clear at once. To scan with no CNN at all, install without the extra (pip uninstall torch torchaudio): Rule 12 is then a no-op.

Note: Auto-repair of corrupted FLAC files is enabled by default — no flag is needed, and it’s lossless and hi-fi-safe. It triggers only on files that can’t be decoded at all; it rebuilds a valid FLAC with the exact same PCM samples (Xiph’s reference flac tool), preserves tags/artwork, verifies the result, and analyses that copy from the temp directory. Your library is not written to unless you pass --repair-in-place, which replaces the broken file and keeps a .corrupted.bak beside it. Healthy files are never rewritten. See Technical Details → Repair for the full procedure.

The update check, and installing the update

Since v2.3.0 the tool asks PyPI once a day whether a newer release exists and, if so, prints one line at the end of the run (the GUI shows an “Update available” link in its header). Since v2.4.0 it also installs it when you say so:

flac-detective --update            # check PyPI now and install the newer release, nothing scanned
beet flacdetective --update        # the same, into beets' Python

On a terminal, a run that ends with the notice asks Install it now? [y/N] — No is the default, and nothing is asked when the output is piped, in --format json without --output, or with --progress-events. The GUI shows an Install vX button next to the link, confirms with a dialog that names the exact command, and tells you to restart when done. The install runs the same interpreter this copy runs in (python -m pip install --upgrade flac-detective), or pipx upgrade flac-detective when this copy was installed by pipx, and it believes a fresh interpreter’s version, not the installer’s exit code. A source checkout (git pull) and the Docker image (docker pull) are told what to do instead of being touched. Nothing is ever installed without that explicit yes.

On Windows the install happens right after you exit. Windows will not let pip replace flac-detective.exe while it is running (and a failed attempt used to leave no package at all), so the tool hands the install to a small detached process that waits for FLAC Detective to exit, then runs pip and checks the version. The CLI tells you so and returns at once; the GUI offers to close. The next time you start FLAC Detective it prints what happened (Update installed: FLAC Detective 2.4.0 (was 2.3.0).); the installer’s full output is in update-install.log beside the update-check cache.

What leaves your machine is one small GET on https://pypi.org/pypi/flac-detective/json — the same page pip reads — with a User-Agent naming this tool and its version; nothing about your files, your paths or your verdicts. The answer is cached for 24 hours (%LOCALAPPDATA%\flac-detective\ on Windows, ~/.cache/flac-detective/ elsewhere), the request times out after two seconds and runs on its own thread while the scan does, and any failure is silent: no network, no notice, no delay. To switch it off:

flac-detective /music --no-update-check          # this run
export FLAC_DETECTIVE_NO_UPDATE_CHECK=1          # every run (the Docker image sets it)

Combining Options

# Verbose + JSON
flac-detective /music --verbose --format json

# Fast scan with custom output
flac-detective /music --sample-duration 15 --output quick-scan.txt

# Let a successful lossless repair replace an undecodable file (keeps a .corrupted.bak)
flac-detective /music --repair-in-place

Progress inside a file (--progress-events)

The progress bar counts finished files, which tells you nothing while a single long track is being analysed. An hour-long file is one tick that arrives when it is already over, so an application driving flac-detective as a subprocess has nothing to show in between and looks frozen.

--progress-events reports the stages within each file, one JSON object per line:

flac-detective /music --progress-events -                 # to stderr
flac-detective /music --progress-events events.ndjson     # to a file

Each line looks like this:

{"event": "stage", "file": "/music/track.flac", "stage": "spectrum", "index": 3, "total": 6}

The stages, always in this order: prepare (copy to a local temp file, or decode a non-native container with ffmpeg), metadata, spectrum, quality, scoring and done. done is emitted exactly once per file whatever the outcome, including a file that failed, so an interface can always release what it is waiting on.

Which stage is the long one depends on the file. On a long track it is quality, which reads the audio to measure clipping, DC offset and silence. On a typical library file scoring can dominate instead, when Rule 1’s FLAC-equivalent re-encode and the heavy rules actually run.

The steps inside quality are reported too, as a second kind of event:

{"event": "substage", "file": "...", "stage": "quality", "detail": "silence", "index": 4, "total": 6}

The steps are clipping, dc_offset, silence, bit_depth, upsampling, and a substage carries the index/total of its parent stage.

Note that clipping, dc_offset and silence arrive together: since 1.15.0 they are computed in a single pass over the audio, so all three genuinely start at the same moment. Announcing them one after another would describe a sequence that no longer happens.

Position inside the scan

That single pass is the longest step of an analysis, and it cannot be broken into smaller named steps. So it reports where it is, as a third kind of event:

{"event": "scan", "file": "...", "stage": "quality", "index": 4, "total": 6, "frames": 26460000, "frames_total": 52920000}

frames out of frames_total is the only honest measure of progress the engine has: it is a position in this one traversal, counted in audio frames, not a fraction of the whole analysis. Positions only move forward, never exceed the total, and the last one is always exactly frames_total, so an interface can tell a finished scan from a stalled one.

At most 21 of these per file — one every 5% of the audio, plus the final exact position. On a 20-minute track that brings the longest silence between two events down to about 5 s, from 16 s.

Filtering by event keeps every earlier integration working: "stage" gives the six stages exactly as 1.14.0 emitted them, "substage" the named steps as 1.14.1 did, and "scan" is simply new.

If you only care about the six stages, filter on event == "stage" and you will see exactly what you saw before — same order, same indices, same keys. Substages are added next to stage events, never woven into them.

There is no percentage, on purpose. Which rules run depends on what the earlier ones found: the authentic fast path returns before the expensive half, --deep bypasses it, Rule 1’s container test is skipped where nothing reads the ratio, and Rules 11–15 each have their own entry condition. The time left inside a file is not knowable when the file is opened, so index/total is a position in a fixed list of stages, never a fraction of the work. A number here would be a progress bar that lies.

- writes to stderr, never stdout, because stdout carries the report under --format json and has to stay parseable. stderr also carries the banner and the log, so match the lines you want and ignore the rest — every event line starts with {"event":

for line in proc.stderr:
    if line.startswith('{"event"'):
        handle(json.loads(line))

Give a file path instead if you want a stream with nothing else in it. Lines are flushed as they happen, so tailing the file works; the file is truncated at start.

From Python, pass a callback instead — same stages, no subprocess:

from flac_detective import FLACAnalyzer


def show(event):
    if event.frames is not None:
        pct = 100 * event.frames / event.frames_total
        print(f"{event.stage} scan {pct:.0f}%")
        return
    where = event.stage if event.detail is None else f"{event.stage}/{event.detail}"
    print(f"{where} ({event.index}/{event.total}) {event.file}")


result = FLACAnalyzer().analyze_file("track.flac", on_progress=show)

The callback only observes: anything it raises is swallowed, and the verdict is the same whether you pass one or not.

Understanding Results

The Four Verdicts

✅ AUTHENTIC (Score ≤ 30)

Meaning: Genuine lossless audio, very high confidence

Typical characteristics:

  • Cutoff frequency at or near Nyquist (22050 Hz for 44.1kHz)

  • No compression artifacts detected

  • High spectral variance

  • May have analog source signatures (vinyl, cassette)

Example:

VERDICT: AUTHENTIC ✅ (Score: 12/150)
REASON: Full spectrum preserved, no artifacts
RECOMMENDATION: File is genuine lossless. Keep as-is.

Action: Keep the file, it’s authentic.


❓ WARNING (Score 31-54)

Meaning: Uncertain case, manual review needed

Typical characteristics:

  • Cutoff slightly below Nyquist (20-21 kHz)

  • Some minor artifacts but protected by other rules

  • Could be legitimate high-quality source

  • Could be borderline transcode

Example:

VERDICT: WARNING ❓ (Score: 45/150)
REASON: Cutoff at 20500 Hz, minor artifacts
RECOMMENDATION: Verify with external tools. Could be legitimate.

Action:

  1. Listen to the file carefully

  2. Check source credibility

  3. Use complementary tool (e.g., Spek for visual spectral analysis)

  4. Consider re-downloading if suspicious


⚠️ SUSPICIOUS (Score 55-85)

Meaning: High confidence MP3 transcode

Typical characteristics:

  • MP3 spectral signature detected (Rule 1: +50 pts)

  • Cutoff matches known MP3 bitrate (128-256 kbps)

  • Compression artifacts present

  • Consistent patterns across file

Example:

VERDICT: SUSPICIOUS ⚠️ (Score: 72/150)
REASON: MP3 192 kbps signature detected
ANALYSIS:
  ✓ Rule 1: +50 pts - CBR pattern at 192 kbps
  ✓ Rule 2: +15 pts - Cutoff at 19500 Hz
RECOMMENDATION: High confidence transcode. Replace if possible.

Action:

  1. Replace file from better source if available

  2. Accept quality loss if no alternative

  3. Document for future reference


❌ FAKE_CERTAIN (Score ≥ 86)

Meaning: Definite MP3 transcode, absolute confidence

Typical characteristics:

  • Multiple MP3 indicators confirmed

  • Strong compression artifacts

  • Suspicious metadata (fake 24-bit)

  • Consistent MP3 patterns throughout

Example:

VERDICT: FAKE_CERTAIN ❌ (Score: 103/150)
REASON: Multiple MP3 signatures confirmed
ANALYSIS:
  ✓ Rule 1: +50 pts - MP3 128 kbps signature
  ✓ Rule 2: +30 pts - Cutoff at 16000 Hz
  ✓ Rule 4: +30 pts - Suspicious 24-bit encoding
  ✓ Rule 13: +45 pts - MDCT quantisation grid detected
RECOMMENDATION: Definitely transcoded. Delete and replace.

Action:

  1. Delete the file

  2. Find authentic source

  3. Report to distributor if applicable

Understanding Rule Contributions

Each rule can add or subtract points:

Positive Rules (Add points → Indicates fake):

  • Rule 1: MP3 Spectral Signature (+50)

  • Rule 2: Low Cutoff Frequency (+30)

  • Rule 4: Suspicious 24-bit (+30)

  • Rule 13: MDCT frame alignment (+25 / +55, by peak ratio)

  • Rule 10: Multi-Segment Consistency (+20)

(Rule 3, “Bitrate Mismatch”, was removed in v1.10: it compared the bitrate Rule 1 had inferred, and across 978 measured files it never once fired without Rule 1.)

Protection Rules (Subtract points → Protects authentic):

  • Rule 5: High Variance Protection (-40)

  • Rule 6: High Quality Protection (-30)

  • Rule 7: Vinyl & Silence Analysis (-100)

  • Rule 8: Nyquist Exception (-50)

  • Rule 11: Cassette Detection (-40, and Rule 1 is not run)

Optional ML Rule (requires pip install "flac-detective[ml]"):

  • Rule 12: CNN Classifier — sharpens borderline verdicts on suspect files; not applied unless the ML extra is installed

Report File Format

FLAC Detective saves a detailed text report:

FLAC AUTHENTICITY ANALYSIS REPORT
Generated: 2026-06-05 14:30:22
Analyzer Version: 1.3.0
Sample Duration: 30.0s
Scan Path: /music/collection
======================================================================

SUMMARY
======================================================================
Total files analyzed: 245
Authentic files: 215 (87.8%)
Warning files: 18 (7.3%)
Suspicious files: 9 (3.7%)
Fake certain files: 3 (1.2%)

======================================================================
DETAILED RESULTS
======================================================================

[Individual file entries follow...]

Real-World Examples

Example 1: Cleaning Your Library

Scenario: You have 1000 FLAC files and want to identify fakes.

# Run analysis
flac-detective ~/Music/FLAC > analysis.txt

# Review summary
head -30 analysis.txt

# Find all fakes
grep "FAKE_CERTAIN" analysis.txt

# Find suspicious files
grep -E "SUSPICIOUS|FAKE_CERTAIN" analysis.txt

Result interpretation:

  • 950 AUTHENTIC → Keep these

  • 35 WARNING → Review manually

  • 12 SUSPICIOUS → Replace if possible

  • 3 FAKE_CERTAIN → Delete immediately


Example 2: Verifying Downloads

Scenario: You downloaded an album from the internet.

# Analyze the album
flac-detective "/downloads/Pink Floyd - DSOTM (2011 Remaster)"

# Check results

Outcomes:

  • All AUTHENTIC → Safe to import to library

  • Some WARNING → Check source reputation, verify samples

  • Any SUSPICIOUS/FAKE → Find better source


Example 3: Pre-Upload Quality Check

Scenario: Before uploading to Bandcamp/streaming service.

# Verify your mastered album
flac-detective "/projects/my-album/masters"

# Ensure all files are AUTHENTIC
# Fix any issues before upload

Example 4: Marketplace Purchase Verification

Scenario: Bought FLAC collection from seller.

# Verify authenticity
flac-detective "/purchased/jazz-collection"

# Calculate fake percentage
# >20% fakes → Request refund
# <5% fakes → Accept (normal variation)

Batch Processing

Process Multiple Folders

#!/bin/bash
# analyze-all.sh

for artist in ~/Music/FLAC/*/; do
    echo "Analyzing: $(basename "$artist")"
    flac-detective "$artist" --output "reports/$(basename "$artist").txt"
done

Find and Move Suspicious Files

#!/bin/bash
# quarantine-fakes.sh

mkdir -p ~/Music/quarantine

# Run analysis and save
flac-detective ~/Music/FLAC --format json > results.json

# Parse JSON and move files (requires jq)
jq -r '.files[] | select(.score >= 55) | .filepath' results.json | while read file; do
    mv "$file" ~/Music/quarantine/
done

Parallel Processing (Advanced)

#!/bin/bash
# Fast parallel analysis using GNU parallel

find ~/Music -name "*.flac" | parallel -j 4 "flac-detective {} --format json >> results.jsonl"

Docker Usage

Basic Docker Commands

# Pull latest image
docker pull ghcr.io/guillain-rdcde/flac_detective:latest

# Analyze directory
docker run --rm \
  -v /path/to/music:/data \
  ghcr.io/guillain-rdcde/flac_detective:latest \
  /data

# Save report outside container
docker run --rm \
  -v /path/to/music:/data \
  -v /path/to/reports:/reports \
  ghcr.io/guillain-rdcde/flac_detective:latest \
  /data --output /reports/report.txt

# Read-only music mount: keep progress.json (resume state), the report and the
# log in a writable volume with --work-dir. (Without it the scan still completes
# — flac-detective falls back to /tmp inside the container — but everything it
# wrote is gone when the container exits.)
docker run --rm \
  -v /path/to/music:/data:ro \
  -v /path/to/reports:/reports \
  ghcr.io/guillain-rdcde/flac_detective:latest \
  /data --work-dir /reports

Docker Compose

Create docker-compose.yml (Compose v2+ no longer requires a top-level version: key):

services:
  flac-detective:
    image: ghcr.io/guillain-rdcde/flac_detective:latest
    volumes:
      - ./music:/data
      - ./reports:/reports
    command: /data --output /reports/analysis.txt

Run:

docker-compose up

Windows Docker Examples

# Windows PowerShell
docker run --rm `
  -v "C:\Users\YourName\Music":/data `
  ghcr.io/guillain-rdcde/flac_detective:latest `
  /data

Best Practices

1. Regular Library Audits

# Monthly check
flac-detective ~/Music/FLAC --output "reports/audit-$(date +%Y%m).txt"

2. Verify Before Archiving

Always check files before long-term storage:

flac-detective /staging/to-archive
# Only archive if all AUTHENTIC

3. Document Questionable Files

Keep a log of WARNING files:

grep "WARNING" report.txt > warnings.txt
# Review periodically

4. Use Multiple Tools for Confirmation

FLAC Detective is excellent but not perfect:

  • Visual inspection with Spek for spectral analysis

  • Listen with quality headphones for audible artifacts

  • Cross-reference with multiple sources when uncertain

5. Understand Your Sources

Different sources have different characteristics:

  • Vinyl rips: May trigger Rule 7 (protected)

  • Cassette transfers: May trigger Rule 11 (protected)

  • High-quality MP3 320: Rule 6 provides some protection

  • Streaming rips: Often SUSPICIOUS or FAKE_CERTAIN

Troubleshooting

Issue: High False Positive Rate

Symptoms: Many authentic files marked as SUSPICIOUS

Causes:

  • Vinyl or cassette sources

  • Aggressive mastering

  • Special audio processing

Solution: Check if files are protected by Rules 7 or 11. If not, file a bug report with samples.


Issue: Slow Performance

Symptoms: Analysis takes >10 seconds per file

Causes:

  • Network drives

  • Very large files (>100MB)

  • Slow disk I/O

Solutions:

# Use shorter sample duration
flac-detective /music --sample-duration 15

# Copy to local disk first
cp -r /network/music /tmp/local-copy
flac-detective /tmp/local-copy

Issue: “ModuleNotFoundError”

Symptoms: Python import errors

Solution:

# Reinstall dependencies
pip install --upgrade flac-detective

# Or install from source
pip install -e ".[dev]"

Issue: Corrupted FLAC Files

Symptoms: “FLAC decoder error” messages

Solution: Auto-repair is enabled by default — just re-run the command and the tool will attempt to repair unreadable files transparently. For manual repair outside FLAC Detective:

flac --verify --decode-through-errors file.flac

Issue: Docker Volume Permissions

Symptoms: “Permission denied” in Docker

Solution (Linux):

# Run with current user
docker run --rm \
  --user $(id -u):$(id -g) \
  -v /path/to/music:/data \
  ghcr.io/guillain-rdcde/flac_detective:latest \
  /data

Advanced Tips

Customize Thresholds (Python)

from flac_detective import FLACAnalyzer

analyzer = FLACAnalyzer(sample_duration=45.0)
# Analyze with custom parameters

Integration with Music Players

# Create playlist of authentic files
flac-detective ~/Music --format json | jq -r '.files[] | select(.score <= 30) | .filepath' > authentic.m3u

Automated Quality Monitoring

# Cron job: daily library check
0 2 * * * /usr/local/bin/flac-detective ~/Music --output ~/reports/daily-$(date +\%Y\%m\%d).txt

Getting More Help


Happy analyzing! For questions, visit GitHub Issues.