Skip to content

Checks and Flags

m4bwav edited this page Nov 7, 2026 · 2 revisions

Numbers catch faults. A person's ear decides. A flag means listen, it is not a verdict, and no flag does not mean a sound is good.

The thresholds are being calibrated. They began as guesses from DSP books. Treat every limit below as provisional, and read the thresholds reference for the current state. Flags never change the exit code.

Flags

Flag Reading Limit
CLIP run of identical samples at the file's own peak 4 samples
DC largest channel mean above -60 dB
CUT_HEAD, CUT_TAIL peak of the first 4 or last 12 samples above -50, -60 dB
LEAD_SILENCE, END_SILENCE time before -40 dB of peak; after -50 dB 0.05 s, 0.25 s
CLICK isolated sample step against its neighbours, outside the attack ratio above 8
NOISE_FLOOR steady 200 ms floor, 20 dB under the peak above -60 dB
NO_HEADROOM peak above -0.1 dB
LENGTH sound length against --seconds off by 25% or 0.05 s
SEAM end-to-start jump, with --loop above 5
SEAM_SPECTRAL spectrum change across the loop point, against the file's 99th percentile change above 1.0
NEAR_DUPLICATES best-lag correlation in a set above 0.98
OUTLIERS a file unlike the rest of a set, for example by level
LEVEL_SPREAD RMS range in a set above 3 dB
TOO_EVEN spread of gaps between onsets below 0.03
SAME_SAMPLE neighbouring hits in a sequence are alike

Flags on sound that is fine

Procedural sounds flag too. One take of each of the twelve recipes:

$ python sfx.py check r/*.wav
beep.wav  0.120s sound 0.122s peak -3.1 rms -6.3 attack 6ms tail 0.11s floor -240 click 3.0  ok
click.wav  0.062s sound 0.056s peak -3.1 rms -18.6 attack 0ms tail 0.06s floor -240 click 0.0  ok
creak.wav  1.200s sound 1.201s peak -3.1 rms -17.7 attack 331ms tail 0.07s floor -240 click 13.6  ok
explosion.wav  2.907s sound 2.746s peak -3.1 rms -20.4 attack 2ms tail 2.78s floor -63 click 3.4  CUT_HEAD
fire.wav  6.000s sound 6.000s peak -3.1 rms -15.3 attack 18ms tail 0.82s floor -20 click 89.6  CLICK
footstep.wav  0.415s sound 0.315s peak -3.1 rms -18.7 attack 50ms tail 0.25s floor -62 click 5.5  ok
modal.wav  0.400s sound 0.395s peak -3.1 rms -26.3 attack 0ms tail 0.04s floor -53 click 0.0  NOISE_FLOOR
retro.wav  0.281s sound 0.277s peak -3.1 rms -9.4 attack 0ms tail 0.19s floor -24 click 0.0  CUT_HEAD
shaker.wav  0.332s sound 0.291s peak -3.1 rms -26.4 attack 28ms tail 0.25s floor -62 click 6.0  ok
switch.wav  0.070s sound 0.062s peak -3.1 rms -18.4 attack 4ms tail 0.06s floor -240 click 5.7  ok
whoosh.wav  0.795s sound 0.764s peak -3.1 rms -16.2 attack 301ms tail 0.37s floor -30 click 3.0  ok
wind.wav  8.000s sound 7.992s peak -3.1 rms -16.6 attack 2083ms tail 5.70s floor -20 click 3.6  ok
4 of 12 flagged; a flag means listen, not reject
$ echo $?
0

A click with CUT_HEAD is a hard start, which a click is meant to have. Waive what the brief wants:

$ python sfx.py check bad_click.wav --waive CLICK
bad_click.wav  0.400s sound 0.395s peak -3.1 rms -26.3 attack 0ms tail 0.04s floor -53 click 357.1  NOISE_FLOOR
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0

Planting a fault

degrade plants a known fault so you can test the checks on your own material. Results on one wood modal hit, whose untouched reading already carries NOISE_FLOOR:

$ python sfx.py check wood.wav
wood.wav  0.400s sound 0.395s peak -3.1 rms -26.3 attack 0ms tail 0.04s floor -53 click 0.0  NOISE_FLOOR
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0
$ python sfx.py check bad_click.wav
bad_click.wav  0.400s sound 0.395s peak -3.1 rms -26.3 attack 0ms tail 0.04s floor -53 click 357.1  CLICK,NOISE_FLOOR
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0
$ python sfx.py check bad_dc.wav
bad_dc.wav  0.400s sound 0.401s peak -3.0 rms -26.1 attack 0ms tail 0.03s floor -42 click 0.0  DC,CUT_HEAD,CUT_TAIL,NOISE_FLOOR
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0
$ python sfx.py check bad_clip.wav
bad_clip.wav  0.400s sound 0.399s peak -3.2 rms -19.9 attack 0ms tail 0.04s floor -41 click 0.0  CLIP,DC,NOISE_FLOOR
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0
$ python sfx.py check bad_pad.wav
bad_pad.wav  2.400s sound 0.395s peak -3.1 rms -34.1 attack 0ms tail 0.40s floor -240 click 0.0  LEAD_SILENCE,END_SILENCE
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0

A planted seam that passed

The seam fault raised neither SEAM nor SEAM_SPECTRAL on a wind bed. It flagged only DC, a side effect of the planted fault:

$ python sfx.py degrade bed_loop.wav bad_seam.wav --fault seam
{"ok": true, "out": "bad_seam.wav", "fault": "seam"}
$ echo $?
0
$ python sfx.py check bad_seam.wav --loop
bad_seam.wav  6.500s sound 6.501s peak -1.4 rms -12.7 attack 4238ms tail 2.26s floor -12 click 2.8 seam 1.7  DC
1 of 1 flagged; a flag means listen, not reject
$ echo $?
0

So listen to every loop around its join, whatever check --loop says. This run used musicwright's seam score when it was installed; the script's own version was not exercised. SEAM_SPECTRAL was calibrated on a different fault, a second half low-passed at 800 Hz: 21 of 29 caught, 0 of 29 clean loops flagged.

What set misses

set finds exact and near-exact copies. It does not catch pitch-shifted copies of one source. Six vary copies of a single footstep are one attack shifted in pitch, and the set comes back clean:

$ python sfx.py vary step.wav --out sv --name v --count 6
{"ok": true, "files": ["sv\\v_01.wav", "sv\\v_02.wav", "sv\\v_03.wav", "sv\\v_04.wav", "sv\\v_05.wav", "sv\\v_06.wav"], "note": "one source shifted in pitch keeps one attack; add more sources if the set machine-guns by ear"}
$ echo $?
0
$ python sfx.py set sv/v_*.wav
{"ok": true, "files": 6, "flags": [], "near_duplicates": [], "outliers": [], "peak_spread_db": 2.61, "rms_spread_db": 2.46, "corr_max": 0.61, "corr_median": 0.273, "attack_dist_median": 0.17, "note": "heuristic; a blind listen decides whether a set machine-guns"}
$ echo $?
0

A clean set does not rule out machine-gunning. Listen.

It can also err the other way. Four modal takes with different seeds flag as near-duplicates, because the recipe's seed changes little in a tonal hit. That is a true warning about the recipe: use material, size or hardness for variety, or another source.

$ python sfx.py set s/hit_*.wav
{"ok": true, "files": 5, "flags": ["NEAR_DUPLICATES"], "near_duplicates": [["hit_01.wav", "hit_02.wav"], ["hit_01.wav", "hit_03.wav"], ["hit_01.wav", "hit_04.wav"], ["hit_01.wav", "hit_05.wav"], ["hit_02.wav", "hit_03.wav"], ["hit_02.wav", "hit_04.wav"], ["hit_02.wav", "hit_05.wav"], ["hit_03.wav", "hit_04.wav"], ["hit_03.wav", "hit_05.wav"], ["hit_04.wav", "hit_05.wav"]], "outliers": [], "peak_spread_db": 0.0, "rms_spread_db": 0.49, "corr_max": 0.996, "corr_median": 0.992, "attack_dist_median": 0.53, "note": "heuristic; a blind listen decides whether a set machine-guns"}
$ echo $?
0

That run holds a fifth file, an exact copy of hit_01.wav, which reads a corr_max of 1.0. Whether a file pitch-shifts into or out of the limit depends on the sound: vary on the tonal wood hit did flag.

A level outlier:

$ python sfx.py set s/hit_03.wav s/hit_04.wav quiet.wav
{"ok": true, "files": 3, "flags": ["NEAR_DUPLICATES", "OUTLIERS", "LEVEL_SPREAD"], "near_duplicates": [["hit_03.wav", "hit_04.wav"], ["hit_03.wav", "quiet.wav"], ["hit_04.wav", "quiet.wav"]], "outliers": [{"file": "quiet.wav", "by": "level"}], "peak_spread_db": 12.0, "rms_spread_db": 12.18, "corr_max": 0.995, "corr_median": 0.992, "attack_dist_median": 1.54, "note": "heuristic; a blind listen decides whether a set machine-guns"}
$ echo $?
0

timing

One sample repeated at an even pace trips both timing flags:

$ python sfx.py sequence s/hit_01.wav --out even.wav --count 12 --jitter 0 --limp 1
{"ok": true, "out": "even.wav", "events": [0.0, 0.55, 1.1, 1.65, 2.2, 2.75, 3.3, 3.85, 4.4, 4.95, 5.5, 6.05], "seconds": 7.0}
$ echo $?
0
$ python sfx.py timing even.wav
{"ok": true, "onsets": 11, "mean_gap_s": 0.55, "gap_cv": 0.003, "neighbour_corr_median": 0.999, "flags": ["TOO_EVEN", "SAME_SAMPLE"]}
$ echo $?
0

Onset counts are estimates: both walks on these pages have 12 hits, and timing counts 11.

Clone this wiki locally