2026-07-03 12:15:47 +02:00
|
|
|
|
tcd - Transcode Detector
|
|
|
|
|
|
=========================
|
|
|
|
|
|
|
|
|
|
|
|
`tcd` analyses an audio file's frequency spectrum to determine whether it is a
|
2026-07-04 09:48:32 +02:00
|
|
|
|
genuine native encode or a *transcode* (a lossy → lossless re-encode). It can
|
2026-07-03 12:15:47 +02:00
|
|
|
|
also detect *upscaling* (a lossy file that has been re-encoded at a higher
|
|
|
|
|
|
bitrate by the same lossy codec, e.g. 128 → 320 kbps MP3).
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-07-03 12:25:21 +02:00
|
|
|
|
Obligatory AI-slop disclaimer
|
|
|
|
|
|
-----------------------------
|
|
|
|
|
|
`tcd` is 98% vibe-coded (a.k.a. "ai slop"). If that's a problem for you, please
|
|
|
|
|
|
kindly just use a different tool. There is also absolutely *NO* guarantee this
|
|
|
|
|
|
will work reliably, be useful in any way, or even make any sense whatsoever.
|
|
|
|
|
|
|
|
|
|
|
|
Careful! Dragons ahead!
|
|
|
|
|
|
-----------------------
|
|
|
|
|
|
`tcd` *can* and absolutely *will* delete your data. Don't blindly use -a, and
|
|
|
|
|
|
please read at least the --help information and *understand* what -a does.
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
---
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
How it works (the short version)
|
|
|
|
|
|
--------------------------------
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
tcd decodes your audio file, converts it to the frequency domain (like a
|
|
|
|
|
|
graph showing how much energy exists at each frequency), then measures several
|
|
|
|
|
|
properties of that frequency graph. Each property is a clue about whether the
|
|
|
|
|
|
audio was produced by a lossy encoder. Combined, these clues give a verdict.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
What tcd displays and what each number means
|
|
|
|
|
|
---------------------------------------------
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 20:01:30 +02:00
|
|
|
|
Here is example output from an MP3 file:
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
```
|
|
|
|
|
|
File: ./08 You Got Me.mp3
|
|
|
|
|
|
Format: mp3
|
|
|
|
|
|
Bitrate: 320 kbps
|
|
|
|
|
|
Sample rate: 44100 Hz
|
|
|
|
|
|
Channels: 2
|
|
|
|
|
|
Windows: 13550
|
|
|
|
|
|
Peak: 47.5 dBFS
|
|
|
|
|
|
Cutoff: 20790 / 22050 Hz = 94.3%
|
|
|
|
|
|
Steepness: 20209 Hz
|
|
|
|
|
|
Roughness: 0.323
|
|
|
|
|
|
Band ratio: 0.555
|
|
|
|
|
|
Noise floor: -56.4 dB
|
|
|
|
|
|
Verdict: NATIVE
|
|
|
|
|
|
Verdict Info: bandwidth used=94.3% (20790/22050 Hz), expected≥90% for 320 kbps
|
|
|
|
|
|
```
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
Each metric is explained below.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Cutoff (20790 / 22050 Hz = 94.3%)
|
|
|
|
|
|
|
|
|
|
|
|
**What it is:** The highest frequency where the audio still has measurable
|
|
|
|
|
|
energy. Everything above this point is silence or noise.
|
|
|
|
|
|
|
|
|
|
|
|
**The Nyquist ceiling:** Digital audio is made of snapshots (samples). For CD
|
|
|
|
|
|
quality (44100 snapshots per second), there is a hard limit: you cannot store
|
|
|
|
|
|
a frequency higher than half the snapshot rate = **22050 Hz**. This is called
|
2026-07-04 20:02:19 +02:00
|
|
|
|
the *Nyquist frequency*. It is a physical ceiling - higher frequencies simply
|
2026-07-04 19:59:09 +02:00
|
|
|
|
cannot exist.
|
|
|
|
|
|
|
|
|
|
|
|
**How lossy encoding changes it:** MP3 and other lossy codecs deliberately cut
|
|
|
|
|
|
off high frequencies to save space. The cutoff gets lower as the bitrate drops:
|
|
|
|
|
|
|
|
|
|
|
|
| Bitrate | Typical cutoff | Audio quality impact |
|
|
|
|
|
|
|---------|---------------|----------------------|
|
|
|
|
|
|
| 320 kbps | ≥20000 Hz (≥90%) | Keeps almost all audible high end |
|
|
|
|
|
|
| 256 kbps | ≥19000 Hz (≥86%) | Still very clean |
|
|
|
|
|
|
| 192 kbps | ~17500 Hz (~79%) | Moderate high-end roll-off |
|
|
|
|
|
|
| 128 kbps | ~16000 Hz (~73%) | Noticeable treble loss |
|
|
|
|
|
|
| 96 kbps | ~13000 Hz (~59%) | Significant high-end missing |
|
|
|
|
|
|
| 64 kbps | ~11000 Hz (~50%) | Sounds dull, heavily filtered |
|
|
|
|
|
|
|
2026-07-04 20:01:30 +02:00
|
|
|
|
**What 94.3% means for the example file:** 20790 / 22050 = 94.3%. The cutoff is very
|
2026-07-04 19:59:09 +02:00
|
|
|
|
close to the theoretical maximum. This is what we expect from a 320 kbps
|
|
|
|
|
|
encode. If this same file showed 54% (~12000 Hz), it would mean the treble
|
|
|
|
|
|
was chopped off by an aggressive low-bitrate encoder, and someone just
|
2026-07-04 20:02:19 +02:00
|
|
|
|
re-encoded it at 320 kbps - the cutoff is permanent and cannot be restored.
|
2026-07-04 19:59:09 +02:00
|
|
|
|
That would be an **UPSCALED** file.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Steepness
|
|
|
|
|
|
|
|
|
|
|
|
**What it measures:** How abruptly the sound drops off *at* the cutoff point.
|
|
|
|
|
|
tcd measures this as the frequency gap between the −20 dB point (still loud)
|
|
|
|
|
|
and the −60 dB cutoff (essentially silent). A narrow gap = a sharp drop.
|
|
|
|
|
|
|
|
|
|
|
|
**The analogy:** Imagine the frequency graph as a mountain ridge. A lossless
|
2026-07-04 20:02:19 +02:00
|
|
|
|
recording rolls off like a natural hillside - gradual, smooth, taking
|
2026-07-04 19:59:09 +02:00
|
|
|
|
thousands of Hz to go from loud to silent. A lossy encoder's lowpass filter
|
2026-07-04 20:02:19 +02:00
|
|
|
|
creates a cliff - a near-vertical drop from audible signal to nothing.
|
2026-07-04 19:59:09 +02:00
|
|
|
|
|
|
|
|
|
|
**What the number means:** Steepness is the width (in Hz) of that drop zone.
|
|
|
|
|
|
The smaller the number, the sharper the cliff:
|
|
|
|
|
|
|
|
|
|
|
|
| Steepness | What it looks like | Likely origin |
|
|
|
|
|
|
|-----------|-------------------|---------------|
|
|
|
|
|
|
| <500 Hz | Brick-wall drop | Lossy encoder (MP3, AAC) |
|
|
|
|
|
|
| 500–2000 Hz | Fairly sharp | Could be lossy or aggressive production filter |
|
|
|
|
|
|
| 2000–5000 Hz | Moderate | Might be natural |
|
|
|
|
|
|
| >5000 Hz | Gentle slope | Natural acoustic roll-off (lossless) |
|
|
|
|
|
|
|
|
|
|
|
|
To understand steepness, imagine a guitar string being plucked. The sound
|
2026-07-04 20:02:19 +02:00
|
|
|
|
naturally fades across many frequencies - the harmonics near the top end of
|
2026-07-04 19:59:09 +02:00
|
|
|
|
your hearing get quieter and quieter over a broad range. This is a gentle
|
|
|
|
|
|
slope. Now imagine someone put a pair of scissors on the frequency spectrum
|
2026-07-04 20:02:19 +02:00
|
|
|
|
and cut everything above a certain note. That sharp edge - the difference
|
|
|
|
|
|
between "still audible" and "completely gone" in just a few hundred Hz - is
|
2026-07-04 19:59:09 +02:00
|
|
|
|
what lossy compression does. The steepness number tells you how sharp that
|
|
|
|
|
|
scissor cut was.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Roughness (0.323)
|
|
|
|
|
|
|
|
|
|
|
|
**What it measures:** How "bumpy" or "irregular" the spectrum looks just
|
|
|
|
|
|
before the cutoff point.
|
|
|
|
|
|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
**The analogy:** Lossy encoding introduces quantization noise - tiny
|
2026-07-04 19:59:09 +02:00
|
|
|
|
rounding errors that are unevenly distributed across frequencies. In the
|
|
|
|
|
|
frequency graph, this looks like a jagged, bumpy line instead of a smooth
|
|
|
|
|
|
one. Think of it like a dirt road vs a paved highway: lossless audio is
|
|
|
|
|
|
smooth, lossy audio is bumpy. Double-encoded audio (a transcode) is even
|
|
|
|
|
|
bumpier because the errors from two encodings stack on top of each other.
|
|
|
|
|
|
|
|
|
|
|
|
**What the number means:**
|
|
|
|
|
|
|
|
|
|
|
|
| Roughness | What it looks like | Likely origin |
|
|
|
|
|
|
|-----------|-------------------|---------------|
|
|
|
|
|
|
| <0.15 | Very smooth | Natural/lossless |
|
|
|
|
|
|
| 0.15–0.30 | Slightly bumpy | Could be lossy single encode |
|
|
|
|
|
|
| 0.30–0.50 | Clearly bumpy | Lossy single encode, or borderline transcode |
|
|
|
|
|
|
| >0.50 | Very jagged | Almost certainly a transcode |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Band ratio (0.555)
|
|
|
|
|
|
|
|
|
|
|
|
**What it measures:** How much high-frequency energy (16–20 kHz) remains
|
|
|
|
|
|
compared to mid-high energy (12–16 kHz).
|
|
|
|
|
|
|
|
|
|
|
|
**Why it matters:** Human hearing is least sensitive above 16 kHz. Lossy
|
|
|
|
|
|
encoders exploit this by spending almost no bits on those frequencies. The
|
|
|
|
|
|
result is that the 16–20 kHz region is much quieter than the 12–16 kHz region.
|
|
|
|
|
|
In native recordings, this drop is modest; in lossy/transcoded material, it
|
|
|
|
|
|
is severe.
|
|
|
|
|
|
|
|
|
|
|
|
**What the number means:** Band ratio = energy in 16–20 kHz band ÷ energy in
|
|
|
|
|
|
12–16 kHz band. A ratio of 1.0 means both bands are equally loud. A ratio of
|
|
|
|
|
|
0.5 means the top band is half as loud.
|
|
|
|
|
|
|
|
|
|
|
|
| Band ratio | What it means |
|
|
|
|
|
|
|------------|---------------|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
| >0.85 | Healthy high end - likely native lossless |
|
|
|
|
|
|
| 0.70–0.85 | Mild roll-off - could be lossy or natural |
|
|
|
|
|
|
| 0.50–0.70 | Significant high-end loss - likely lossy |
|
|
|
|
|
|
| <0.50 | Severe high-end loss - almost certainly lossy or transcoded |
|
2026-07-04 19:59:09 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Noise floor (-56.4 dB)
|
|
|
|
|
|
|
|
|
|
|
|
**What it measures:** The average noise level in the highest quarter of the
|
|
|
|
|
|
frequency range (roughly 16500–22050 Hz).
|
|
|
|
|
|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
**The analogy:** Imagine listening in a quiet room - the background hiss is
|
|
|
|
|
|
very low. Now imagine that same room with a fan running - the background
|
2026-07-04 19:59:09 +02:00
|
|
|
|
noise rises. A lossy encoder introduces quantization noise that raises the
|
|
|
|
|
|
"background hiss" in the high frequencies.
|
|
|
|
|
|
|
|
|
|
|
|
**What the number means:** This is measured in decibels (dB). More negative =
|
|
|
|
|
|
quieter (better). Less negative = noisier (worse):
|
|
|
|
|
|
|
|
|
|
|
|
| Noise floor | What it means |
|
|
|
|
|
|
|-------------|---------------|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
| −90 to −110 dB | Very clean - native lossless |
|
|
|
|
|
|
| −70 to −90 dB | Moderate - could be lossy or quiet lossless |
|
|
|
|
|
|
| −50 to −70 dB | Noisy - likely lossy |
|
|
|
|
|
|
| >−50 dB | Very noisy - almost certainly lossy or transcoded |
|
2026-07-04 19:59:09 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
How tcd combines these clues into a verdict
|
|
|
|
|
|
---------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
tcd does not rely on any single metric. It combines them in stages, like a
|
|
|
|
|
|
detective building a case.
|
|
|
|
|
|
|
|
|
|
|
|
### Scenario 1: The input file is lossy (MP3, AAC, etc.)
|
|
|
|
|
|
|
|
|
|
|
|
The file already claims to be lossy. The question is: was it *originally*
|
|
|
|
|
|
encoded at the stated bitrate, or was it re-encoded from a lower bitrate?
|
|
|
|
|
|
|
|
|
|
|
|
**The check:** tcd compares the cutoff against what is expected for that
|
2026-07-03 12:15:47 +02:00
|
|
|
|
bitrate:
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
| Stated bitrate | Expected cutoff |
|
|
|
|
|
|
|----------------|-----------------|
|
|
|
|
|
|
| <192 kbps | ≥75% of Nyquist |
|
|
|
|
|
|
| 192–255 kbps | ≥85% of Nyquist |
|
|
|
|
|
|
| ≥256 kbps | ≥90% of Nyquist |
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
If the actual cutoff is **more than 8 percentage points lower** than expected,
|
|
|
|
|
|
the file is **UPSCALED**. For example, a file claiming 320 kbps (expecting
|
|
|
|
|
|
≥90%) but showing a cutoff of 70% (≈15400 Hz) would be flagged as upscaled
|
|
|
|
|
|
from ~96 kbps.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
Otherwise it is **NATIVE** - a genuine single encode at this bitrate.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
### Scenario 2: The input file is lossless (FLAC, WAV, ALAC, etc.)
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
The file claims to be lossless. The question is: was it actually created by
|
|
|
|
|
|
decoding a lossy file and re-encoding to lossless?
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
tcd uses a **two-layer** check:
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
**Layer 1 - Cutoff + Steepness (primary):**
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
| Cutoff range | Max steepness allowed | If exceeded → |
|
|
|
|
|
|
|-------------|----------------------|---------------|
|
|
|
|
|
|
| <50% of Nyquist | 4000 Hz | TRANSCODE |
|
|
|
|
|
|
| 50–70% | 3000 Hz | TRANSCODE |
|
|
|
|
|
|
| 70–80% | 2000 Hz | TRANSCODE |
|
|
|
|
|
|
| 80–90% | 1200 Hz | TRANSCODE |
|
|
|
|
|
|
| ≥90% | 500 Hz | TRANSCODE |
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
This works because lossy cutoffs are always sharp (low steepness). A lossless
|
|
|
|
|
|
recording that happens to have a low cutoff (e.g., a muddy recording with
|
2026-07-04 20:02:19 +02:00
|
|
|
|
little treble) would still have a *gradual* roll-off (high steepness) - you
|
2026-07-04 19:59:09 +02:00
|
|
|
|
need both a low cutoff **and** a sharp drop to convict.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
**Layer 2 - Roughness + Band ratio (secondary):**
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
If Layer 1 did not trigger but the cutoff is above 80%, tcd checks roughness
|
|
|
|
|
|
and band ratio. This catches transcodes where the cutoff happens to be high
|
|
|
|
|
|
enough to pass Layer 1 but the spectrum is still bumpy and depleted in the
|
|
|
|
|
|
top band:
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
| Roughness | Band ratio | If matched → |
|
|
|
|
|
|
|-----------|------------|--------------|
|
|
|
|
|
|
| >0.40 | any | TRANSCODE |
|
|
|
|
|
|
| >0.30 | <0.90 | TRANSCODE |
|
|
|
|
|
|
| >0.20 | <0.85 | TRANSCODE |
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
If neither layer triggers, the file is **GENUINE** (native lossless).
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### The verdicts at a glance
|
|
|
|
|
|
|
|
|
|
|
|
| Verdict | Input codec | What it means |
|
|
|
|
|
|
|---------|------------|---------------|
|
2026-07-04 20:02:19 +02:00
|
|
|
|
| **NATIVE** | lossy | Encoded once at the stated bitrate - genuine |
|
2026-07-04 19:59:09 +02:00
|
|
|
|
| **UPSCALED** | lossy | Originally encoded at a lower bitrate, then re-encoded higher |
|
2026-07-04 20:02:19 +02:00
|
|
|
|
| **GENUINE** | lossless | Appears to be native lossless - no evidence of lossy origin |
|
2026-07-04 19:59:09 +02:00
|
|
|
|
| **TRANSCODE** | lossless | Originated from a lossy source, decoded to lossless |
|
|
|
|
|
|
| **SILENT** | any | No detectable audio content |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
Confidence score
|
|
|
|
|
|
----------------
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
A continuous **confidence** (0–100 %) is computed using the same metrics with
|
|
|
|
|
|
a sliding scale, providing a graded measure of how certain the tool is about
|
|
|
|
|
|
its verdict.
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
Auto-remove mode (`-a`)
|
|
|
|
|
|
------------------------
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
When `-a` is passed, any file that is not classified as NATIVE or GENUINE is
|
2026-07-04 09:48:32 +02:00
|
|
|
|
automatically deleted after analysis. This is useful for batch cleanup of
|
2026-07-04 20:02:19 +02:00
|
|
|
|
corrupt or transcoded libraries. Careful - this will eat data.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
Why the method is (somewhat!) scientifically reliable
|
2026-07-04 19:59:09 +02:00
|
|
|
|
------------------------------------------------------
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
### 1. Lossy encoding leaves a permanent spectral fingerprint
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
Every lossy audio codec discards information. The most obvious form is a
|
2026-07-04 20:02:19 +02:00
|
|
|
|
**lowpass filter** - once applied, the frequencies above the cutoff are gone
|
2026-07-04 19:59:09 +02:00
|
|
|
|
forever. Decoding back to PCM and re-encoding to lossless cannot restore them.
|
|
|
|
|
|
This means a "lossless" FLAC file made from an MP3 will contain the MP3's
|
|
|
|
|
|
permanent spectral cutoff.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
### 2. Steepness catches the filter shape
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
Lossy encoders use sharp digital filters (brick-wall style) that drop from
|
|
|
|
|
|
audible to silent in a few hundred Hz. Natural acoustic sources (voice,
|
|
|
|
|
|
instruments, room ambience) roll off gradually over many kHz. A drop steeper
|
|
|
|
|
|
than 2 kHz at any cutoff position is extremely unlikely to occur naturally.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
- **MP3 (ISO/IEC 11172-3):** typical roll-off of several hundred Hz to ~2 kHz
|
|
|
|
|
|
- **AAC (ISO/IEC 13818-7):** sharper, often 200–800 Hz
|
|
|
|
|
|
- **Vorbis:** variable but always steeper than natural
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
### 3. Roughness detects double-encoding noise
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
When audio is lossy-encoded, quantization noise is shaped to be masked by the
|
|
|
|
|
|
music. Re-encoding adds a *second* layer of noise-shaping, creating
|
2026-07-03 12:15:47 +02:00
|
|
|
|
irregularities in the spectrum that are statistically unlikely in a single
|
|
|
|
|
|
encode.
|
|
|
|
|
|
|
|
|
|
|
|
### 4. Band ratio exploits the Fletcher–Munson curves
|
|
|
|
|
|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
Human hearing is least sensitive above 16 kHz. Lossy encoders exploit this by
|
2026-07-04 19:59:09 +02:00
|
|
|
|
spending almost no bits there. In native recordings, the 16–20 kHz region is
|
|
|
|
|
|
typically only 2–6 dB quieter than 12–16 kHz (band ratio 0.5–1.0). In
|
|
|
|
|
|
transcoded material it is often 10–20 dB quieter (band ratio < 0.3).
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
### 5. Multiple independent metrics prevent false positives
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
No single metric is perfectly reliable. A low cutoff could occur in a genuine
|
|
|
|
|
|
recording that used an aggressive lowpass during mastering. By requiring
|
|
|
|
|
|
**both** a low cutoff **and** a sharp roll-off (primary), or **both** high
|
|
|
|
|
|
roughness **and** a low band ratio (secondary), the tool avoids false
|
|
|
|
|
|
positives.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
### 6. The upscaling detector is conservative
|
|
|
|
|
|
|
2026-07-04 19:59:09 +02:00
|
|
|
|
For lossy files, an 8-percentage-point margin is subtracted before flagging a
|
|
|
|
|
|
file as upscaled. This accounts for encoder variability and prevents false
|
|
|
|
|
|
positives on legitimate encodes that simply use a conservative lowpass.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
Usage
|
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
tcd [options] <audio-file>
|
|
|
|
|
|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
-t, --threshold PCT Overall detection sensitivity (1-99). Controls all
|
|
|
|
|
|
decision thresholds: transition bandwidth, roughness,
|
|
|
|
|
|
and band ratio. Maps to -40 dB cutoff level (1, least
|
|
|
|
|
|
sensitive) through -80 dB (99, most sensitive).
|
|
|
|
|
|
[default: 50]. 50 is neutral; lower = fewer detections,
|
|
|
|
|
|
higher = more detections. Adjust in small steps.
|
|
|
|
|
|
-f, --fft-size N FFT size (power of 2) [default: 4096]
|
|
|
|
|
|
-d, --duration SEC Max seconds to analyze [default: 60]
|
|
|
|
|
|
-r, --recursive Recurse into subdirectories
|
|
|
|
|
|
-F, --full Analyze entire file (overrides --duration)
|
|
|
|
|
|
-v, --verbose Verbose output
|
|
|
|
|
|
-s, --visual Graphical spectrum visualization (TUI)
|
|
|
|
|
|
-V Alias for -s
|
|
|
|
|
|
-a, --auto-remove Automatically remove non-native files
|
|
|
|
|
|
-h, --help Show this help
|
2026-07-03 12:15:47 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Exit codes:
|
|
|
|
|
|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
| Code | Meaning |
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|------|-----------------------------------|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
| 0 | NATIVE or GENUINE (file is clean) |
|
|
|
|
|
|
| 1 | UPSCALED or TRANSCODE detected |
|
|
|
|
|
|
| 2 | SILENT (no detectable content) |
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
Limitations
|
|
|
|
|
|
-----------
|
|
|
|
|
|
|
2026-07-04 09:48:32 +02:00
|
|
|
|
- **Very short files** (< `fft_size` samples) cannot be analysed. Use `-f`
|
|
|
|
|
|
to reduce the FFT size.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- **Already-lowpass-filtered material** (e.g. deliberate 15 kHz LPF during
|
2026-07-04 09:48:32 +02:00
|
|
|
|
mastering) may trigger false positives. The confidence score helps assess
|
|
|
|
|
|
borderline cases.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- **High-bitrate lossy encodes** (320 kbps MP3, 256 kbps AAC) have cutoffs
|
2026-07-04 09:48:32 +02:00
|
|
|
|
very close to Nyquist and may not be distinguishable from lossless by
|
|
|
|
|
|
cutoff alone. The tool relies on roughness and band ratio in this regime.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- **Synthetic or electronic music** with no natural high-frequency content
|
2026-07-04 09:48:32 +02:00
|
|
|
|
may have anomalous spectra. Use the visual mode (`-s`) to inspect the
|
|
|
|
|
|
spectrum manually.
|
2026-07-03 12:15:47 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
|
|
- ISO/IEC 11172-3:1993 - Coding of moving pictures and associated audio for
|
2026-07-04 09:48:32 +02:00
|
|
|
|
digital storage media at up to about 1.5 Mbit/s, Part 3: Audio (MPEG-1
|
|
|
|
|
|
Audio Layer III, "MP3").
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- ISO/IEC 13818-7:2006 - Generic coding of moving pictures and associated
|
2026-07-04 09:48:32 +02:00
|
|
|
|
audio information, Part 7: Advanced Audio Coding (AAC).
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- Zwicker, E. & Fastl, H. - *Psychoacoustics: Facts and Models*, Springer,
|
2026-07-04 09:48:32 +02:00
|
|
|
|
1999 (Fletcher–Munson equal-loudness contours).
|
2026-07-03 12:15:47 +02:00
|
|
|
|
- Lerch, A. - *An Introduction to Audio Content Analysis*, Wiley, 2012
|
2026-07-04 09:48:32 +02:00
|
|
|
|
(spectral features for audio forensics).
|