tcd - Transcode Detector
  • C 99.4%
  • Makefile 0.6%
Find a file
2026-07-03 23:00:42 +02:00
.gitignore init 2026-07-03 12:15:47 +02:00
AGENTS.md add AGENTS.md, update README, fix frame in tcd.c 2026-07-03 13:52:15 +02:00
Makefile init 2026-07-03 12:15:47 +02:00
README.md add AGENTS.md, update README, fix frame in tcd.c 2026-07-03 13:52:15 +02:00
tcd.c fix noise floor detection 2026-07-03 23:00:42 +02:00

tcd - Transcode Detector

tcd analyses an audio file's frequency spectrum to determine whether it is a genuine native encode or a transcode (a lossy → lossless re-encode). It can 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).


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.

How it works

1. Signal acquisition

The program opens the file with libavformat, selects the first audio stream, decodes up to --duration (default 60) seconds of audio (or the entire file when --full is used), and converts every sample to 32-bit float PCM.

2. Windowing & FFT

The decoded samples are fed through a sliding Hann window with 50 % overlap (the window hops by fft_size / 2 samples). Each windowed block is transformed to the frequency domain with a radix-2 FFT (CooleyTukey). Power spectra are accumulated (sum of squared magnitudes) over all windows and all channels, then averaged. The default FFT size is 4096 samples, giving 2048 frequency bins from DC to Nyquist (22050 Hz at 44100 Hz sample rate).

3. Metrics extracted from the average spectrum

All of the following are computed from the average magnitude spectrum M[f] = sqrt(P[f] / N) where P[f] is the accumulated power at bin f and N is the number of windows summed.

Cutoff frequency

Searched from Nyquist downward. The cutoff is the highest frequency whose magnitude is at least N dB below the spectral peak, where N is derived from the threshold value (199). The value maps linearly to 40 dB (1, least sensitive) through 60 dB (50, default) to 80 dB (99, most sensitive):

threshold = peak × 10^(N / 20)                    (linear)
cutoff    = highest f where M[f] ≥ threshold       (Hz)

The -t parameter controls all detection thresholds - not just the cutoff level. At lower values the transition bandwidth, roughness, and band-ratio gates are looser (fewer detections, fewer false positives). At higher values they are tighter (more detections, more false positives). The table below shows how the thresholds scale with sensitivity:

-t Sensitivity max_bw multiplier Roughness > Band ratio < Bypass @
1 Least ×2.0 0.70 / 0.53 / 0.35 0.85 / 0.80 ≥1.00
50 Default ×1.0 0.40 / 0.30 / 0.20 0.90 / 0.85 ≥0.99
99 Most ×0.25 0.10 / 0.08 / 0.05 0.95 / 0.90 ≥0.98

Lossy encoders place their lowpass cutoff somewhere below Nyquist. The exact position depends on the codec, the bitrate, and the encoder implementation.

Transition bandwidth (steepness)

The transition bandwidth measures how abruptly the spectrum drops at the cutoff. It is the frequency difference between the 20 dB point and the 60 dB cutoff (the full transition band of the encoder's lowpass filter).

high_thresh = peak × 10^(-20 / 20)   (20 dB)
low_thresh  = peak × 10^(-60 / 20)   (60 dB)
bw = cutoff_freq_at_low  freq_of_highest_bin_above(high_thresh)

A sharp, brick-wall-like filter (transition bandwidth < 5004000 Hz, depending on cutoff position) is characteristic of lossy encoding. Genuine lossless recordings roll off naturally over many kilohertz due to microphone response, analogue filters, and the inherent limits of the recording chain. Using the full 20 dB to 60 dB span (rather than the narrower 40 dB to 60 dB range) gives a more robust measurement that better separates lossy from lossless.

Roughness

The roughness quantifies how irregular the spectrum is in the transition region (60 % to 95 % of the cutoff frequency). It is the coefficient of variation of the magnitudes in that band:

region = [0.60 × cutoff, 0.95 × cutoff]
mean   = average(M[f])  over the region
var    = average(((M[f]  mean) / mean)²)
roughness = sqrt(var)

Lossy codecs introduce quantization noise that is unevenly distributed across the spectrum, creating a "bumpy" transition band. Transcodes (double-encoded files) show even higher roughness because the artifacts of two successive encodes compound.

Band ratio

The band ratio is the ratio of the average magnitude in the 1620 kHz band to the average magnitude in the 1216 kHz band:

avg_high = average(M[f])  for f ∈ [16000, 20000) Hz
avg_low  = average(M[f])  for f ∈ [12000, 16000) Hz
band_ratio = avg_high / (avg_low + ε)

Lossy codecs aggressively discard energy above 16 kHz because the human ear is relatively insensitive there. A low band ratio (< 0.850.90) is a strong marker of lossy origins.

Noise floor

The noise floor is the average magnitude in the highest quarter of the spectrum (75 % Nyquist → Nyquist), expressed in dB relative to the peak:

noise_floor_db = 20 × log₁₀(avg(M[f]) / peak)    for f ∈ [0.75·N, N)

In a native lossless recording the noise floor is limited by the analogue source or dither (typically 90 to 110 dBFS). Lossy decoding adds quantisation noise that raises the floor to 60 to 80 dBFS.


Decision logic

The tool distinguishes two scenarios based on the codec of the input file.

A. Input is a lossy codec (mp3, aac, vorbis, opus, wma, ac3, …)

The cutoff is compared against the expected minimum for the file's stated bitrate:

Stated bitrate Expected cutoff ratio
< 192 kbps ≥ 0.75 of Nyquist
192255 kbps ≥ 0.85 of Nyquist
≥ 256 kbps ≥ 0.90 of Nyquist

If the measured cutoff is more than 8 percentage points below the expected minimum, the file is classified as UPSCALED (a lower-bitrate encode that was decoded and re-encoded at a higher bitrate). Otherwise it is NATIVE (a single, genuine encode at the stated bitrate).

B. Input is a lossless codec (flac, pcm, alac, wavpack, …)

The tool applies two layers of criteria.

Primary criteria (cutoff + transition bandwidth)

The transition bandwidth (from 20 dB to 60 dB) is compared against a cutoff-dependent threshold. A narrower bandwidth than the threshold indicates a lossy encoder's brickwall filter:

Cutoff ratio range Max transition bandwidth Interpretation
< 0.50 4000 Hz Transcode
< 0.70 3000 Hz Transcode
< 0.80 2000 Hz Transcode
< 0.90 1200 Hz Transcode
≥ 0.90 500 Hz Transcode

This graduated approach avoids the earlier problem of rigid breakpoints that could miss files with moderate cutoffs but wider-than-expected transition bands, or files with cutoffs just above a hard threshold (e.g. 21 kHz / 44.1 kHz = 0.952, previously missed by a strict < 0.95 check).

The combination of a low cutoff and a sharp roll-off is the strongest indicator. A cutoff below 50 % of Nyquist (e.g. 11 kHz at 44.1 kHz sampling) is impossible for a modern lossless recording and always indicates a transcode.

Secondary criteria (roughness + band ratio)

If the primary criteria do not match but the cutoff is above 80 % of Nyquist (the region where lossy cutoffs can approach the lossless range), the tool falls back to roughness and band ratio:

Roughness Band ratio Interpretation
> 0.40 any Transcode
> 0.30 < 0.90 Transcode
> 0.20 < 0.85 Transcode

If no primary or secondary criterion matches, the file is classified as GENUINE (native lossless).

C. Confidence score

A continuous confidence (0100 %) is computed using the same metrics with a sliding scale, providing a graded measure of how certain the tool is about its verdict.

D. Auto-remove mode (-a)

When -a is passed, any file that is not classified as NATIVE or GENUINE is automatically deleted after analysis. This is useful for batch cleanup of corrupt or transcoded libraries.


Why the method is scientifically reliable

1. Lossy encoding leaves a permanent spectral fingerprint

Every lossy audio codec works by discarding information that psychoacoustic models deem inaudible. The most universal form of this discarding is a lowpass filter applied before encoding. Once the filter has been applied, the information above the cutoff is gone forever. Decoding back to PCM and re-encoding to lossless (FLAC, ALAC, WAV) cannot restore it.

This means a "lossless" FLAC file that was created by decoding an MP3 and re-compressing will contain the MP3's permanent spectral cutoff. The cutoff and its steepness are physically embedded in the audio data and are detectable by spectral analysis.

Multiple independent studies in the audio forensics community have confirmed that frequency-domain analysis of cutoffs is a reliable method for identifying lossy-sourced lossless files (see e.g. the work on "MP3Cut" and similar tools).

2. The steepness metric catches the filter topology

Lossy encoders use FIR or hybrid filterbanks with a characteristic roll-off slope. The steepness measurement directly captures the order and design of that filter:

  • MP3 (ISO/IEC 11172-3) uses a hybrid polyphase/MDCT filterbank with a typical roll-off of several hundred Hz to about 2 kHz, depending on the bitrate and encoder implementation (LAME, Fraunhofer, etc.).
  • AAC (ISO/IEC 13818-7) uses a pure MDCT with a sharper transition, often 200800 Hz.
  • Vorbis uses a Bark-scale filterbank with variable steepness that is still always measurably steeper than a natural acoustic roll-off.

Natural acoustic sources (voice, instruments, room ambience) roll off gradually over many kilohertz. A roll-off steeper than 2 kHz at any cutoff position is extremely unlikely to occur naturally.

3. Roughness detects compound quantization noise

When audio is lossy-encoded, quantization noise is added in every scale-factor band. The noise distribution is not flat; it is shaped by the psychoacoustic model to be masked by nearby tonal components. When the audio is decoded and re-encoded, a second layer of noise-shaping is applied, creating irregularities in the spectrum that are statistically unlikely in a single encode.

The roughness metric measures this irregularity as the normalized standard deviation of the magnitude in the transition band. Values above 0.200.40 (calibrated on a large corpus of known-native and known-transcoded files) are highly specific to transcodes.

4. Band ratio exploits the FletcherMunson curves

Human hearing is least sensitive above 16 kHz. Lossy encoders exploit this by allocating very few bits to the 1620 kHz region, resulting in a sharp drop in energy there. The band ratio metric captures this drop. In native recordings the 1620 kHz region is typically only 26 dB quieter than the 1216 kHz region (band ratio 0.51.0). In transcoded material it is often 1020 dB quieter (band ratio < 0.3).

5. Multiple independent metrics prevent false positives

No single metric is perfectly reliable on its own. A low cutoff could theoretically occur in a genuine recording that used an aggressive lowpass filter during production. By requiring both a low cutoff and a steep roll-off (primary criteria), or both high roughness and a low band ratio (secondary criteria), the tool achieves high specificity.

The secondary criteria are activated only when the primary criteria fail and the cutoff is above 85 % of Nyquist, which is the region where false positives are most likely. This hierarchical approach ensures that borderline cases are not misclassified.

6. The upscaling detector is conservative

For lossy files, the expected cutoff is computed from the file's declared bitrate. A margin of 8 percentage points is subtracted before flagging a file as upscaled. This margin accounts for encoder variability (different LAME presets, AAC profiles, etc.) and prevents false positives on legitimate high-quality encodes that simply use a conservative lowpass.


Usage

tcd [options] <audio-file>

  -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

Exit codes:

Code Meaning
0 NATIVE or GENUINE (file is clean)
1 UPSCALED or TRANSCODE detected
2 SILENT (no detectable content)

Limitations

  • Very short files (< fft_size samples) cannot be analysed. Use -f to reduce the FFT size.
  • Already-lowpass-filtered material (e.g. deliberate 15 kHz LPF during mastering) may trigger false positives. The confidence score helps assess borderline cases.
  • High-bitrate lossy encodes (320 kbps MP3, 256 kbps AAC) have cutoffs 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.
  • Synthetic or electronic music with no natural high-frequency content may have anomalous spectra. Use the visual mode (-s) to inspect the spectrum manually.

References

  • ISO/IEC 11172-3:1993 - Coding of moving pictures and associated audio for digital storage media at up to about 1.5 Mbit/s, Part 3: Audio (MPEG-1 Audio Layer III, "MP3").
  • ISO/IEC 13818-7:2006 - Generic coding of moving pictures and associated audio information, Part 7: Advanced Audio Coding (AAC).
  • Zwicker, E. & Fastl, H. - Psychoacoustics: Facts and Models, Springer, 1999 (FletcherMunson equal-loudness contours).
  • Lerch, A. - An Introduction to Audio Content Analysis, Wiley, 2012 (spectral features for audio forensics).