
An audio clip can sound fine in a browser preview and still be the wrong file to ship. The export may be shorter than expected, use a codec your playback stack does not support, or switch from mono to stereo between runs.
Those are file-level problems. A short metadata pass can catch them before a reviewer spends time listening to every clip.
The script below scans a directory, asks FFprobe for a few basic properties, and writes the results as CSV. It does not judge whether a voice sounds natural. Think of it as the first step before listening, script verification, and rights review.
What the preflight checks
For each supported file, the report records:
- duration;
- audio codec;
- sample rate;
- channel count;
- a short review note.
Files shorter than one second are marked for another look. That threshold is only a prompt. A 400 ms sound effect may be intentional, while a 400 ms narration export probably deserves investigation.
The report cannot tell you whether the script is correct, a name is pronounced properly, the speaker gave consent, or the license permits publication. Clean metadata does not make an audio asset ready to ship.
1. Confirm that FFprobe is available
FFprobe is installed with FFmpeg. Check it from a terminal:
ffprobe -version
If the command is not found, install FFmpeg for your operating system and add its binary directory to PATH.
2. Add the Python scanner
Save this file as voice_preflight.py. It uses the Python standard library and calls the local ffprobe executable. It does not require an API key or a cloud service.
import csv
import json
import shutil
import subprocess
import sys
from pathlib import Path
AUDIO_TYPES = {".wav", ".mp3", ".m4a", ".flac", ".ogg", ".opus"}
def probe(path):
command = [
"ffprobe", "-v", "error", "-select_streams", "a:0",
"-show_entries", "stream=codec_name,sample_rate,channels:format=duration",
"-of", "json", str(path),
]
result = subprocess.run(command, capture_output=True, text=True, check=True)
data = json.loads(result.stdout)
if not data.get("streams"):
raise ValueError("no audio stream")
stream = data["streams"][0]
raw = data.get("format", {}).get("duration")
seconds = float(raw) if raw not in (None, "", "N/A") else None
return seconds, stream.get("codec_name", ""), stream.get("sample_rate", ""), stream.get("channels", "")
def main(folder):
if shutil.which("ffprobe") is None:
raise SystemExit("ffprobe not found: install FFmpeg and add it to PATH")
if not folder.is_dir():
raise SystemExit(f"Not a directory: {folder}")
files = sorted(p for p in folder.rglob("*") if p.is_file() and p.suffix.lower() in AUDIO_TYPES)
if not files:
raise SystemExit("No supported audio files found")
writer = csv.writer(sys.stdout)
writer.writerow(["file", "seconds", "codec", "sample_rate_hz", "channels", "review_note"])
for path in files:
try:
seconds, codec, rate, channels = probe(path)
notes = []
if seconds is None:
notes.append("duration unavailable")
elif seconds < 1:
notes.append("very short; check export")
if not rate:
notes.append("sample rate unavailable")
if channels not in (1, 2):
notes.append("unusual channel count")
writer.writerow([
str(path.relative_to(folder)),
f"{seconds:.2f}" if seconds is not None else "",
codec, rate, channels, "; ".join(notes) or "metadata OK",
])
except subprocess.CalledProcessError:
writer.writerow([str(path.relative_to(folder)), "", "", "", "", "cannot decode file or find audio stream"])
except (ValueError, json.JSONDecodeError) as error:
writer.writerow([str(path.relative_to(folder)), "", "", "", "", f"invalid metadata: {error}"])
if __name__ == "__main__":
if len(sys.argv) != 2:
raise SystemExit("Usage: python voice_preflight.py path/to/clips")
main(Path(sys.argv[1]))
Put the exported files in a directory named clips, then run:
python voice_preflight.py clips > voice_report.csv
The command above works as written in Bash and cmd.exe. Windows PowerShell 5.1 handles native output redirection differently and may write UTF-16LE CSV with blank rows. From PowerShell 5.1, use the following tested form to preserve the expected CSV layout:
cmd /c "python voice_preflight.py clips > voice_report.csv"
The scanner searches subdirectories and includes WAV, MP3, M4A, FLAC, OGG, and Opus files. Other extensions are ignored. A missing directory, a directory with no supported files, or an unavailable ffprobe executable stops the run with a clear message. A damaged audio file produces an error row without stopping the rest of the scan.
Here is the unchanged output from a local test with synthetic WAV files. These were generated test tones, not recordings or output from a voice-cloning product.
file,seconds,codec,sample_rate_hz,channels,review_note
long.wav,1.80,pcm_s16le,16000,1,metadata OK
short.wav,0.40,pcm_s16le,16000,1,very short; check export
The sample-rate column describes the file; it does not grade it. Whether 16 kHz, 24 kHz, or 48 kHz is acceptable depends on the application and its playback pipeline. The reported duration is container metadata and may be unavailable for some inputs, which is why the script leaves the CSV field empty instead of treating a missing value as zero.
3. Review the audio itself
Do not automate this part away. Listen to the exact downloaded file that may be published, not only to a browser preview.
- Compare the recording with the approved script. Pay close attention to names, numbers, missing words, and repeated phrases.
- Listen for clipped consonants, abrupt endings, odd pauses, and emphasis that changes the meaning.
- Ask a qualified speaker to review languages you do not understand. Language availability does not guarantee accurate pronunciation.
- Confirm that the exported file, rather than a separate preview, works in the target application.
- Check consent, licensing, and any disclosure required for synthetic speech.
For a small project, the CSV and a reviewer checkmark may be enough. A larger pipeline can add target-specific assertions later, such as an allowed codec list or a required channel count. Those should reflect the real playback environment rather than a generic definition of “good audio.”
Where the generator fits
The scanner does not know which service created a file. It works the same way with a recording, TTS output, or a cloned voice.
As one example of the surrounding workflow, FreeVoiceClone currently describes generation and preview support across 500+ languages. Its free previews include a light audible watermark. Saving a clean, watermark-free file uses a download pass; a pass by itself does not add commercial rights. Free-tier downloads are for personal use, while downloads made under Plus or Pro include commercial permission subject to the service terms and any third-party rights.
That distinction belongs in the preflight because the technically valid file is not automatically the legally usable file. The script has no integration with the service and makes no claim about its output quality. Only inspect and publish files you are authorized to use.
Top comments (0)