foley.qc#
Tier-0 deterministic audio QC for foley (research report 08 §3).
Pure, per-clip range-checks over a floating-point waveform in [-1, 1]:
clipping, true-peak, DC offset, whole-clip silence, SNR, edge clicks, loudness
(LUFS), duration, and NaN/Inf sanity. Every threshold is an explicit
QCThresholds field — there are no inline policy literals — so the
whole table is a single, overridable source of truth.
- Zero-dependency import contract:
This module imports stdlib only at the top level.
numpyis lazy-imported inside each function body (likefoley.audio), soimport foley.qcsucceeds on a bare install with no scientific stack.measure_lufs()additionally lazy-importspyloudnormand returnsNonewhen it (or a measurable clip) is absent; everything else is numpy-only.- Waveform convention:
samplesis a float array shaped(frames,)(mono) or(frames, channels). dBFS is20·log10(|x|)with full scale at 1.0.
Typical use (at ingest, a later phase):
report = run_qc(working_array, sample_rate)
sound_record.qc = report.to_dict() # becomes filterable metadata
Module Attributes
BS.1770 integrated-loudness gating block = 400 ms; a clip shorter than one block cannot be measured ( |
|
The shipped default thresholds; the default for every keyword below. |
Functions
|
Largest per-channel absolute DC offset, |
|
Detect hard (flat-topped) clipping. |
|
Clip duration in seconds: |
|
Estimate SNR in dB (advisory — a busy-street SFX legitimately scores low). |
|
Return |
|
Return |
|
Integrated loudness (LUFS, ITU-R BS.1770-4) via |
|
Return |
|
Run every Tier-0 check and fold the results into a |
|
Inter-sample true-peak level in dBTP. |
Classes
|
Per-clip Tier-0 QC result. |
|
Overall verdict for a clip (subclasses |
|
All Tier-0 QC defaults (report 08 §3 table), each an explicit field. |
- foley.qc.DEFAULT_QC_THRESHOLDS = QCThresholds(clip_full_scale=0.999, clip_min_run=3, clip_reject_ratio=0.0001, clip_reject_run=10, true_peak_max_dbtp=-1.0, true_peak_oversample=4, dc_offset_fail=0.01, dc_offset_warn=0.001, silence_rms_dbfs=-60.0, snr_clean_db=20.0, snr_quiet_percentile=10.0, snr_frame_s=0.025, snr_hop_s=0.01, edge_rel_peak_dbfs=-40.0, edge_fade_s=0.01, lufs_gate_floor=-70.0, lufs_outlier_lu=6.0, duration_min_s=0.1, deliver_min_sample_rate=44100)#
The shipped default thresholds; the default for every keyword below.
- foley.qc.LUFS_MIN_BLOCK_S: float = 0.4#
BS.1770 integrated-loudness gating block = 400 ms; a clip shorter than one block cannot be measured (
pyloudnormraises), someasure_lufs()returnsNonefor it. This is a fixed property of the algorithm, not a tunable QC policy threshold, hence a module constant rather than a field.
- class foley.qc.QCReport(duration_s, sample_rate, channels, clipped_ratio, clipped_max_run, dc_offset, rms_dbfs, is_silent, needs_edge_fade, has_nan_inf, true_peak_dbtp=None, snr_db=None, loudness_lufs=None, status=QCStatus.pass_, notes=<factory>)[source]#
Bases:
objectPer-clip Tier-0 QC result.
Mirrors the fields the
SoundRecordschema already carries (duration_s,sample_rate,channels,loudness_lufs) plus the deterministic check outputs, an overallstatus, and human-readablenotesfor every firing condition. Serialize withto_dict()intoSoundRecord.qc.
- class foley.qc.QCStatus(*values)[source]#
-
Overall verdict for a clip (subclasses
strso it is JSON-safe).
- class foley.qc.QCThresholds(clip_full_scale=0.999, clip_min_run=3, clip_reject_ratio=0.0001, clip_reject_run=10, true_peak_max_dbtp=-1.0, true_peak_oversample=4, dc_offset_fail=0.01, dc_offset_warn=0.001, silence_rms_dbfs=-60.0, snr_clean_db=20.0, snr_quiet_percentile=10.0, snr_frame_s=0.025, snr_hop_s=0.01, edge_rel_peak_dbfs=-40.0, edge_fade_s=0.01, lufs_gate_floor=-70.0, lufs_outlier_lu=6.0, duration_min_s=0.1, deliver_min_sample_rate=44100)[source]#
Bases:
objectAll Tier-0 QC defaults (report 08 §3 table), each an explicit field.
Grouped by check. Pass a customized instance to
run_qc()(or the per-check keyword arguments) to override any threshold without editing code.
- foley.qc.dc_offset(samples)[source]#
Largest per-channel absolute DC offset,
max_c |mean_n x[n, c]|.- Return type:
- foley.qc.detect_clipping(samples, *, full_scale=0.999, min_run=3)[source]#
Detect hard (flat-topped) clipping.
A frame is “hot” when any channel reaches
|x| >= full_scale. Only maximal hot runs of length>= min_runcount as clip events.- Parameters:
- Return type:
- Returns:
(clipped_ratio, max_run_length)— the fraction of frames inside counting runs, and the longest counting run ((0.0, 0)if none).
- foley.qc.duration_s(samples, sample_rate)[source]#
Clip duration in seconds:
frames / sample_rate.- Return type:
- foley.qc.estimate_snr(samples, sample_rate, *, quiet_percentile=10.0, frame_s=0.025, hop_s=0.01)[source]#
Estimate SNR in dB (advisory — a busy-street SFX legitimately scores low).
The noise floor is the mean short-time RMS of the quietest
quiet_percentilepercent of frames; the signal level is the whole-clip RMS. A near-noise-free clip (quiet frames -> ~0) yields a very high value; an exactly-zero floor returnsinfand a silent clip returns-inf.- Parameters:
samples (
ndarray) – Waveform in[-1, 1](down-mixed to mono internally).sample_rate (
int) – Sample rate in Hz (sizes the frames).quiet_percentile (
float) – Percent of quietest frames forming the noise floor.frame_s (
float) – Short-time frame length in seconds.hop_s (
float) – Hop between frames in seconds.
- Return type:
- Returns:
SNR in dB.
- foley.qc.has_nan_inf(samples)[source]#
Return
Trueif any sample isNaNorInf(corrupt-clip guard).- Return type:
- foley.qc.is_silent(samples, *, rms_floor_dbfs=-60.0)[source]#
Return
Truewhen whole-clip RMS falls belowrms_floor_dbfs.A zero (exactly silent) clip has RMS
0->-infdBFS ->True.- Return type:
- foley.qc.measure_lufs(samples, sample_rate, *, gate_floor_lufs=-70.0, min_block_s=0.4)[source]#
Integrated loudness (LUFS, ITU-R BS.1770-4) via
pyloudnorm(lazy).Returns
Nonewhenpyloudnormis unavailable, the clip is shorter than one gating block (min_block_s), the samples are non-finite, or the measured loudness is at/below the gate floor (near-silent / unstable — do not amplify, just flag).
- foley.qc.needs_edge_fade(samples, *, rel_peak_dbfs=-40.0)[source]#
Return
Truewhen the first or last sample sits aboverel_peak_dbfsrelative to the clip peak — i.e. a nonzero boundary that clicks under narration and needs a short fade.- Return type:
- foley.qc.run_qc(samples, sample_rate, *, thresholds=QCThresholds(clip_full_scale=0.999, clip_min_run=3, clip_reject_ratio=0.0001, clip_reject_run=10, true_peak_max_dbtp=-1.0, true_peak_oversample=4, dc_offset_fail=0.01, dc_offset_warn=0.001, silence_rms_dbfs=-60.0, snr_clean_db=20.0, snr_quiet_percentile=10.0, snr_frame_s=0.025, snr_hop_s=0.01, edge_rel_peak_dbfs=-40.0, edge_fade_s=0.01, lufs_gate_floor=-70.0, lufs_outlier_lu=6.0, duration_min_s=0.1, deliver_min_sample_rate=44100))[source]#
Run every Tier-0 check and fold the results into a
QCReport.- Status rules (evaluated in order):
FAIL if
has_nan_infORis_silentORclipped_max_run >= clip_reject_runORclipped_ratio > clip_reject_ratioORduration_s < duration_min_s. WARN ifdc_offset > dc_offset_failORneeds_edge_fadeOR (snr_dbis a finite value< snr_clean_db) OR (true_peak_dbtpis a finite value> true_peak_max_dbtp). Otherwise PASS.
Each firing condition appends a human-readable string to
notes. Two thresholds are intentionally NOT evaluated on a single source clip here because they belong to later stages: the library-median loudness-outlier check (+/- lufs_outlier_lu, a library-level concern) and the delivery sample-rate target (deliver_min_sample_rate, enforced at the weave/master stage).- Parameters:
samples (
ndarray) – Waveform in[-1, 1](mono or(frames, channels)).sample_rate (
int) – Sample rate in Hz.thresholds (
QCThresholds) – Overridable QC thresholds (defaults to shipped values).
- Return type:
- Returns:
A populated
QCReport.
- foley.qc.true_peak_dbtp(samples, sample_rate, *, oversample=4)[source]#
Inter-sample true-peak level in dBTP.
Each channel is band-limited-upsampled
oversample``x (numpy FFT), the peak magnitude is taken across all channels, and converted to dBTP. Returns ``-inffor a fully silent clip.sample_rateis accepted for interface symmetry (FFT interpolation is rate-independent).- Return type: