█████╗ ██╗ ██╗██████╗ ██╗ ██████╗
██╔══██╗██║ ██║██╔══██╗██║██╔═══██╗
███████║██║ ██║██║ ██║██║██║ ██║
██╔══██║██║ ██║██║ ██║██║██║ ██║
██║ ██║╚██████╔╝██████╔╝██║╚██████╔╝
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
███████╗██╗██╗ ████████╗███████╗██████╗
██╔════╝██║██║ ╚══██╔══╝██╔════╝██╔══██╗
█████╗ ██║██║ ██║ █████╗ ██████╔╝
██╔══╝ ██║██║ ██║ ██╔══╝ ██╔══██╗
██║ ██║███████╗██║ ███████╗██║ ██║
╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝╚═╝ ╚═╝
Quality Filter & Speaker Pipeline
An automated tool that goes through a pile of audio and tells you which recordings are clean enough to keep.
You point the pipeline at a folder of audio files or a HuggingFace dataset, and it checks every recording in two stages:
Each recording ends up labelled good, uncertain, or bad. The results are
written to JSON files you can use to keep only the good audio.
Everything runs on CPU — no GPU needed. The run is resumable: stop it
with Ctrl+C and start it again, it continues where it left off.
The pipeline uses three pre-trained models. They are already included in the repo (or downloaded automatically) — you do not train anything.
| Model | Stage | What it is for |
|---|---|---|
| V1 | Quality | Narrowband audio — sample rate ≤ 24 kHz (phone-quality, older recordings). Extracts 12 acoustic metrics and scores how likely the audio is bad. |
| V2 | Quality | Wideband audio — sample rate > 24 kHz (modern, full-quality recordings). Extracts 34 acoustic metrics, normalizes loudness, then scores it. |
| Pyannote | Speaker overlap | A 17 MB speech-segmentation model that detects whether several people speak simultaneously. Downloaded automatically on first run. |
Why two quality models (V1 / V2)? Low- and high-sample-rate audio behave very differently acoustically. One model for both would be inaccurate, so the pipeline looks at each file's sample rate and automatically picks V1 or V2 — you do not choose.
The Pyannote model runs only on files the quality filter already marked
good, so it never wastes time on audio that is already rejected.
For a full technical description — why two models, what each one measures, and how verdicts are produced — see MODELS.md.
make install auto-detects a compatible interpreter)makeffmpeg — install with sudo apt-get install ffmpeggit clone https://github.com/KaniTTS-research-team/audio_filter.git
cd audio_filter
make install
make install checks for ffmpeg, creates a venv/ folder, and installs all
Python dependencies (pinned to exact tested versions). It takes a few minutes.
make run
At launch the pipeline asks where to take the audio from:
📥 Data source
Enter a FULL PATH to a local folder, or a HuggingFace dataset name.
>
Type one of:
/home/user/my_audio. The pipeline scans it recursively for
.wav .mp3 .flac .ogg .opus .m4a files.username/dataset-name. Requires login
(see below). An s3://bucket/path also works.You can set a default in config.yaml (input.source) and just press
Enter at the prompt to use it.
make login
Paste a token from huggingface.co/settings/tokens.
This step is required — the quality models (V1 + V2) are downloaded from a private HuggingFace repository, so your account needs access to it. Login is also used to read HuggingFace datasets.
| Command | Description |
|---|---|
make install | Create venv/ and install dependencies |
make login | Authenticate with HuggingFace (required — models live on HF) |
make run | Run the pipeline |
make clean | Remove the venv/ directory |
make help | Show the command reference |
All results are written to the results/ folder (configurable — see §7):
| File | What is inside |
|---|---|
all_filter_results.json | Quality verdict (good / uncertain / bad) and bad_prob for every file |
all_features_full.json | All raw acoustic metrics for every file |
all_speaker_results.json | Speaker-overlap result for every file the quality filter passed |
all_filter_metadata.json | The final merged file — quality + features + speaker, one record per audio |
bad_prob | Verdict | Meaning |
|---|---|---|
| low | good | Clean audio — keep it |
| middle | uncertain | Borderline — review manually |
| high | bad | Poor quality — reject |
| Status | Meaning |
|---|---|
GOOD | One speaker — keep it |
UNCERTAIN | Possible overlap — review manually |
BAD | Multiple speakers overlap — reject |
TOO_SHORT | Shorter than 2 s — not checked |
To keep only clean audio, take the records from all_filter_metadata.json
where the quality verdict is good and the speaker status is GOOD.
The quality filter scores each file with bad_prob (0.0–1.0) and assigns a
verdict from two cut-offs per model:
bad_prob < good_below -> good
bad_prob >= bad_above -> bad
in between -> uncertain
All cut-offs live in config.yaml and are safe to edit.
Setting in config.yaml | Controls | Default |
|---|---|---|
quality_filter.v1.good_below | good upper bound for narrowband audio (V1) | 0.35 |
quality_filter.v1.bad_above | bad lower bound for narrowband audio (V1) | 0.55 |
quality_filter.v2.good_below | good upper bound for wideband audio (V2) | 0.30 |
quality_filter.v2.bad_above | bad lower bound for wideband audio (V2) | 0.50 |
speaker_filter.overlap_threshold | Base speaker-overlap cut-off (auto-adjusted by sample rate) | 0.25 |
Raise bad_above → looser (fewer files rejected). Lower it → stricter.
Example: quality is too strict and rejects clean files →
raise v1.bad_above from 0.55 to 0.65.
Too much bad audio gets through → lower it.
The speaker-overlap threshold adapts automatically to the sample rate:
| Sample rate | Lenient bound | Strict bound |
|---|---|---|
| ≤ 24 kHz | threshold − 0.05 | threshold + 0.05 |
| 24–32 kHz | max(threshold, 0.30) | max(threshold + 0.10, 0.40) |
| > 32 kHz | max(threshold, 0.60) | max(threshold + 0.20, 0.80) |
Everything is in config.yaml. Open it in any text editor — every value
has a comment. Below is what each section does.
input — data sourceinput:
source: "" # default answer for the launch prompt
folder_batch_size: 500 # local-folder mode: audio files processed per batch
| Key | Description |
|---|---|
source | Default data source. A full folder path or a HuggingFace dataset name. Leave empty ("") to be asked every time. |
folder_batch_size | When processing a local folder, how many audio files to load and filter at once. Lower it if you run out of RAM. |
hf_dataset — HuggingFace / S3 optionsUsed only when the source is a HuggingFace or S3 dataset. Ignored for local folders.
hf_dataset:
sub_name: null # dataset subset (e.g. 'clean'), or null
split: train # train / test / validation
audio_column_name: audio # name of the audio column
id_column_name: ID # name of the sample-id column
These tell the pipeline which columns of the dataset hold the audio and the ID.
pipeline — download settings (HuggingFace / S3 mode only)pipeline:
batch_size: 3 # parquet files per filter batch
download_batch_size: 6 # parquet files downloaded per cycle
local_path: ./data # where downloaded files are stored
quality_filterquality_filter:
workers: 8 # parallel CPU processes
v1: { good_below: 0.35, bad_above: 0.55, target_sr: 24000 }
v2: { good_below: 0.30, bad_above: 0.50, target_sr: 44100, target_lufs: -23.0 }
workers should not exceed your CPU core count. Verdict zones — see §6.
speaker_filterspeaker_filter:
workers: 8 # parallel CPU processes
overlap_threshold: 0.25
save_settingssave_settings:
local: results # folder for the result JSON files
| Key | Description |
|---|---|
local | Where the all_*.json result files are written. Change it to put results elsewhere. |
Progress is saved after every batch in filter_progress.json (local folders)
and auto_progress.json (HuggingFace datasets). If the run stops, make run
again — already-processed files are skipped. A pipeline.lock file prevents two
runs at once.
ffmpeg not found — install it: sudo apt-get install ffmpeg.
No compatible Python found — install Python 3.10, 3.11, 3.12, or 3.13.
Folder not found at the launch prompt — you typed a path that does not
exist. Use the full absolute path.
Out of memory — lower input.folder_batch_size (folder mode) or
pipeline.batch_size (HuggingFace mode).
Runs slowly — increase quality_filter.workers and
speaker_filter.workers, but never above your CPU core count.
Another pipeline is running — if you are sure no other run is active,
delete pipeline.lock.
HuggingFace login fails — run make login again with a fresh token from
huggingface.co/settings/tokens.
audio_filter/
├── main.py # Entry point
├── make_figures.py # Builds per-metric V1/V2 figures into fig/
├── config.yaml # All settings
├── Makefile # make install / login / run / clean
├── requirements.txt # Pinned Python dependencies
├── README.md # This file
├── MODELS.md # V1/V2 quality models — how they work
├── PROJECT_MAP.md # File-by-file role map
├── LICENSE # Apache 2.0
├── fig/ # Metric figures and experiments
│ ├── v1/ # V1 (narrowband) per-metric plots + README
│ ├── v2/ # V2 (wideband) per-metric plots + README
│ └── sample_rate_experiments/ # Real-SR detection (sr_or.py) + 2 experiments
└── utils/
├── config_manager.py # Typed config loader
├── pipeline_manager.py # Launch prompt + download/filter loop
├── dataset_processor.py # Loads audio (folder or parquet), batching
├── result_merger.py # Merges quality + speaker results
├── logging_config.py # Quiets noisy libraries
├── style.py # Colored console output
├── quality_filter/ # Dual quality model (V1 + V2)
└── speaker_filter/ # Pyannote speaker-overlap detector
This project is licensed under Apache 2.0 — see LICENSE.
The speaker-overlap stage uses a third-party model, downloaded at runtime and not included in this repository:
onnx-community/pyannote-segmentation-3.0
— an ONNX export of segmentation-3.0 from
pyannote.audio (Hervé Bredin et
al.), distributed under the MIT license.It is governed by its own license, not by this project's Apache 2.0 license.
13 commits
Python
89.5%
Makefile
10.5%
█████╗ ██╗ ██╗██████╗ ██╗ ██████╗
██╔══██╗██║ ██║██╔══██╗██║██╔═══██╗
███████║██║ ██║██║ ██║██║██║ ██║
██╔══██║██║ ██║██║ ██║██║██║ ██║
██║ ██║╚██████╔╝██████╔╝██║╚██████╔╝
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
███████╗██╗██╗ ████████╗███████╗██████╗
██╔════╝██║██║ ╚══██╔══╝██╔════╝██╔══██╗
█████╗ ██║██║ ██║ █████╗ ██████╔╝
██╔══╝ ██║██║ ██║ ██╔══╝ ██╔══██╗
██║ ██║███████╗██║ ███████╗██║ ██║
╚═╝ ╚═╝╚══════╝╚═╝ ╚══════╝╚═╝ ╚═╝
Quality Filter & Speaker Pipeline
An automated tool that goes through a pile of audio and tells you which recordings are clean enough to keep.
You point the pipeline at a folder of audio files or a HuggingFace dataset, and it checks every recording in two stages:
Each recording ends up labelled good, uncertain, or bad. The results are
written to JSON files you can use to keep only the good audio.
Everything runs on CPU — no GPU needed. The run is resumable: stop it
with Ctrl+C and start it again, it continues where it left off.
The pipeline uses three pre-trained models. They are already included in the repo (or downloaded automatically) — you do not train anything.
| Model | Stage | What it is for |
|---|---|---|
| V1 | Quality | Narrowband audio — sample rate ≤ 24 kHz (phone-quality, older recordings). Extracts 12 acoustic metrics and scores how likely the audio is bad. |
| V2 | Quality | Wideband audio — sample rate > 24 kHz (modern, full-quality recordings). Extracts 34 acoustic metrics, normalizes loudness, then scores it. |
| Pyannote | Speaker overlap | A 17 MB speech-segmentation model that detects whether several people speak simultaneously. Downloaded automatically on first run. |
Why two quality models (V1 / V2)? Low- and high-sample-rate audio behave very differently acoustically. One model for both would be inaccurate, so the pipeline looks at each file's sample rate and automatically picks V1 or V2 — you do not choose.
The Pyannote model runs only on files the quality filter already marked
good, so it never wastes time on audio that is already rejected.
For a full technical description — why two models, what each one measures, and how verdicts are produced — see MODELS.md.
make install auto-detects a compatible interpreter)makeffmpeg — install with sudo apt-get install ffmpeggit clone https://github.com/KaniTTS-research-team/audio_filter.git
cd audio_filter
make install
make install checks for ffmpeg, creates a venv/ folder, and installs all
Python dependencies (pinned to exact tested versions). It takes a few minutes.
make run
At launch the pipeline asks where to take the audio from:
📥 Data source
Enter a FULL PATH to a local folder, or a HuggingFace dataset name.
>
Type one of:
/home/user/my_audio. The pipeline scans it recursively for
.wav .mp3 .flac .ogg .opus .m4a files.username/dataset-name. Requires login
(see below). An s3://bucket/path also works.You can set a default in config.yaml (input.source) and just press
Enter at the prompt to use it.
make login
Paste a token from huggingface.co/settings/tokens.
This step is required — the quality models (V1 + V2) are downloaded from a private HuggingFace repository, so your account needs access to it. Login is also used to read HuggingFace datasets.
| Command | Description |
|---|---|
make install | Create venv/ and install dependencies |
make login | Authenticate with HuggingFace (required — models live on HF) |
make run | Run the pipeline |
make clean | Remove the venv/ directory |
make help | Show the command reference |
All results are written to the results/ folder (configurable — see §7):
| File | What is inside |
|---|---|
all_filter_results.json | Quality verdict (good / uncertain / bad) and bad_prob for every file |
all_features_full.json | All raw acoustic metrics for every file |
all_speaker_results.json | Speaker-overlap result for every file the quality filter passed |
all_filter_metadata.json | The final merged file — quality + features + speaker, one record per audio |
bad_prob | Verdict | Meaning |
|---|---|---|
| low | good | Clean audio — keep it |
| middle | uncertain | Borderline — review manually |
| high | bad | Poor quality — reject |
| Status | Meaning |
|---|---|
GOOD | One speaker — keep it |
UNCERTAIN | Possible overlap — review manually |
BAD | Multiple speakers overlap — reject |
TOO_SHORT | Shorter than 2 s — not checked |
To keep only clean audio, take the records from all_filter_metadata.json
where the quality verdict is good and the speaker status is GOOD.
The quality filter scores each file with bad_prob (0.0–1.0) and assigns a
verdict from two cut-offs per model:
bad_prob < good_below -> good
bad_prob >= bad_above -> bad
in between -> uncertain
All cut-offs live in config.yaml and are safe to edit.
Setting in config.yaml | Controls | Default |
|---|---|---|
quality_filter.v1.good_below | good upper bound for narrowband audio (V1) | 0.35 |
quality_filter.v1.bad_above | bad lower bound for narrowband audio (V1) | 0.55 |
quality_filter.v2.good_below | good upper bound for wideband audio (V2) | 0.30 |
quality_filter.v2.bad_above | bad lower bound for wideband audio (V2) | 0.50 |
speaker_filter.overlap_threshold | Base speaker-overlap cut-off (auto-adjusted by sample rate) | 0.25 |
Raise bad_above → looser (fewer files rejected). Lower it → stricter.
Example: quality is too strict and rejects clean files →
raise v1.bad_above from 0.55 to 0.65.
Too much bad audio gets through → lower it.
The speaker-overlap threshold adapts automatically to the sample rate:
| Sample rate | Lenient bound | Strict bound |
|---|---|---|
| ≤ 24 kHz | threshold − 0.05 | threshold + 0.05 |
| 24–32 kHz | max(threshold, 0.30) | max(threshold + 0.10, 0.40) |
| > 32 kHz | max(threshold, 0.60) | max(threshold + 0.20, 0.80) |
Everything is in config.yaml. Open it in any text editor — every value
has a comment. Below is what each section does.
input — data sourceinput:
source: "" # default answer for the launch prompt
folder_batch_size: 500 # local-folder mode: audio files processed per batch
| Key | Description |
|---|---|
source | Default data source. A full folder path or a HuggingFace dataset name. Leave empty ("") to be asked every time. |
folder_batch_size | When processing a local folder, how many audio files to load and filter at once. Lower it if you run out of RAM. |
hf_dataset — HuggingFace / S3 optionsUsed only when the source is a HuggingFace or S3 dataset. Ignored for local folders.
hf_dataset:
sub_name: null # dataset subset (e.g. 'clean'), or null
split: train # train / test / validation
audio_column_name: audio # name of the audio column
id_column_name: ID # name of the sample-id column
These tell the pipeline which columns of the dataset hold the audio and the ID.
pipeline — download settings (HuggingFace / S3 mode only)pipeline:
batch_size: 3 # parquet files per filter batch
download_batch_size: 6 # parquet files downloaded per cycle
local_path: ./data # where downloaded files are stored
quality_filterquality_filter:
workers: 8 # parallel CPU processes
v1: { good_below: 0.35, bad_above: 0.55, target_sr: 24000 }
v2: { good_below: 0.30, bad_above: 0.50, target_sr: 44100, target_lufs: -23.0 }
workers should not exceed your CPU core count. Verdict zones — see §6.
speaker_filterspeaker_filter:
workers: 8 # parallel CPU processes
overlap_threshold: 0.25
save_settingssave_settings:
local: results # folder for the result JSON files
| Key | Description |
|---|---|
local | Where the all_*.json result files are written. Change it to put results elsewhere. |
Progress is saved after every batch in filter_progress.json (local folders)
and auto_progress.json (HuggingFace datasets). If the run stops, make run
again — already-processed files are skipped. A pipeline.lock file prevents two
runs at once.
ffmpeg not found — install it: sudo apt-get install ffmpeg.
No compatible Python found — install Python 3.10, 3.11, 3.12, or 3.13.
Folder not found at the launch prompt — you typed a path that does not
exist. Use the full absolute path.
Out of memory — lower input.folder_batch_size (folder mode) or
pipeline.batch_size (HuggingFace mode).
Runs slowly — increase quality_filter.workers and
speaker_filter.workers, but never above your CPU core count.
Another pipeline is running — if you are sure no other run is active,
delete pipeline.lock.
HuggingFace login fails — run make login again with a fresh token from
huggingface.co/settings/tokens.
audio_filter/
├── main.py # Entry point
├── make_figures.py # Builds per-metric V1/V2 figures into fig/
├── config.yaml # All settings
├── Makefile # make install / login / run / clean
├── requirements.txt # Pinned Python dependencies
├── README.md # This file
├── MODELS.md # V1/V2 quality models — how they work
├── PROJECT_MAP.md # File-by-file role map
├── LICENSE # Apache 2.0
├── fig/ # Metric figures and experiments
│ ├── v1/ # V1 (narrowband) per-metric plots + README
│ ├── v2/ # V2 (wideband) per-metric plots + README
│ └── sample_rate_experiments/ # Real-SR detection (sr_or.py) + 2 experiments
└── utils/
├── config_manager.py # Typed config loader
├── pipeline_manager.py # Launch prompt + download/filter loop
├── dataset_processor.py # Loads audio (folder or parquet), batching
├── result_merger.py # Merges quality + speaker results
├── logging_config.py # Quiets noisy libraries
├── style.py # Colored console output
├── quality_filter/ # Dual quality model (V1 + V2)
└── speaker_filter/ # Pyannote speaker-overlap detector
This project is licensed under Apache 2.0 — see LICENSE.
The speaker-overlap stage uses a third-party model, downloaded at runtime and not included in this repository:
onnx-community/pyannote-segmentation-3.0
— an ONNX export of segmentation-3.0 from
pyannote.audio (Hervé Bredin et
al.), distributed under the MIT license.It is governed by its own license, not by this project's Apache 2.0 license.
13 commits
Python
89.5%
Makefile
10.5%