KaniTTS-research-team/audio_filter

Python

0

13 commits

updated Jun 10, 2026

See the code

README

Audio Filter Pipeline

   █████╗ ██╗   ██╗██████╗ ██╗ ██████╗
  ██╔══██╗██║   ██║██╔══██╗██║██╔═══██╗
  ███████║██║   ██║██║  ██║██║██║   ██║
  ██╔══██║██║   ██║██║  ██║██║██║   ██║
  ██║  ██║╚██████╔╝██████╔╝██║╚██████╔╝
  ╚═╝  ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
  ███████╗██╗██╗  ████████╗███████╗██████╗
  ██╔════╝██║██║  ╚══██╔══╝██╔════╝██╔══██╗
  █████╗  ██║██║     ██║   █████╗  ██████╔╝
  ██╔══╝  ██║██║     ██║   ██╔══╝  ██╔══██╗
  ██║     ██║███████╗██║   ███████╗██║  ██║
  ╚═╝     ╚═╝╚══════╝╚═╝   ╚══════╝╚═╝  ╚═╝
       Quality Filter & Speaker Pipeline

An automated tool that goes through a pile of audio and tells you which recordings are clean enough to keep.


1. What it does

You point the pipeline at a folder of audio files or a HuggingFace dataset, and it checks every recording in two stages:

  1. Quality filter — rejects audio that is noisy, clipped, robotic, or bandwidth-limited.
  2. Speaker overlap filter — rejects audio where two or more people talk at the same time.

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.


2. The three models

The pipeline uses three pre-trained models. They are already included in the repo (or downloaded automatically) — you do not train anything.

ModelStageWhat it is for
V1QualityNarrowband audio — sample rate ≤ 24 kHz (phone-quality, older recordings). Extracts 12 acoustic metrics and scores how likely the audio is bad.
V2QualityWideband audio — sample rate > 24 kHz (modern, full-quality recordings). Extracts 34 acoustic metrics, normalizes loudness, then scores it.
PyannoteSpeaker overlapA 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.


3. Install

Prerequisites

  • Linux (Ubuntu / Debian recommended)
  • Python 3.10–3.13 (make install auto-detects a compatible interpreter)
  • make
  • ffmpeg — install with sudo apt-get install ffmpeg

Download and set up

git 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.


4. Run

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:

  • A local folder — the full path to a directory with audio files, e.g. /home/user/my_audio. The pipeline scans it recursively for .wav .mp3 .flac .ogg .opus .m4a files.
  • A HuggingFace dataset — e.g. 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.

Log in to HuggingFace first

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.

All commands

CommandDescription
make installCreate venv/ and install dependencies
make loginAuthenticate with HuggingFace (required — models live on HF)
make runRun the pipeline
make cleanRemove the venv/ directory
make helpShow the command reference

5. What you get

All results are written to the results/ folder (configurable — see §7):

FileWhat is inside
all_filter_results.jsonQuality verdict (good / uncertain / bad) and bad_prob for every file
all_features_full.jsonAll raw acoustic metrics for every file
all_speaker_results.jsonSpeaker-overlap result for every file the quality filter passed
all_filter_metadata.jsonThe final merged file — quality + features + speaker, one record per audio

Quality verdicts

bad_probVerdictMeaning
lowgoodClean audio — keep it
middleuncertainBorderline — review manually
highbadPoor quality — reject

Speaker-overlap verdicts

StatusMeaning
GOODOne speaker — keep it
UNCERTAINPossible overlap — review manually
BADMultiple speakers overlap — reject
TOO_SHORTShorter 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.


6. Tuning the thresholds

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.yamlControlsDefault
quality_filter.v1.good_belowgood upper bound for narrowband audio (V1)0.35
quality_filter.v1.bad_abovebad lower bound for narrowband audio (V1)0.55
quality_filter.v2.good_belowgood upper bound for wideband audio (V2)0.30
quality_filter.v2.bad_abovebad lower bound for wideband audio (V2)0.50
speaker_filter.overlap_thresholdBase speaker-overlap cut-off (auto-adjusted by sample rate)0.25

Raise bad_abovelooser (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 rateLenient boundStrict bound
≤ 24 kHzthreshold − 0.05threshold + 0.05
24–32 kHzmax(threshold, 0.30)max(threshold + 0.10, 0.40)
> 32 kHzmax(threshold, 0.60)max(threshold + 0.20, 0.80)

7. Configuration reference

Everything is in config.yaml. Open it in any text editor — every value has a comment. Below is what each section does.

input — data source

input:
  source: ""                # default answer for the launch prompt
  folder_batch_size: 500    # local-folder mode: audio files processed per batch
KeyDescription
sourceDefault data source. A full folder path or a HuggingFace dataset name. Leave empty ("") to be asked every time.
folder_batch_sizeWhen 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 options

Used 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_filter

quality_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_filter

speaker_filter:
  workers: 8                # parallel CPU processes
  overlap_threshold: 0.25

save_settings

save_settings:
  local: results            # folder for the result JSON files
KeyDescription
localWhere the all_*.json result files are written. Change it to put results elsewhere.

How resuming works

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.


Troubleshooting

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.


Project structure

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

License

This project is licensed under Apache 2.0 — see LICENSE.

Third-party model

The speaker-overlap stage uses a third-party model, downloaded at runtime and not included in this repository:

It is governed by its own license, not by this project's Apache 2.0 license.

Contributors

Arsen2453

13 commits

KaniTTS-research-team/audio_filter

Python

0

13 commits

updated Jun 10, 2026

See the code

README

Audio Filter Pipeline

   █████╗ ██╗   ██╗██████╗ ██╗ ██████╗
  ██╔══██╗██║   ██║██╔══██╗██║██╔═══██╗
  ███████║██║   ██║██║  ██║██║██║   ██║
  ██╔══██║██║   ██║██║  ██║██║██║   ██║
  ██║  ██║╚██████╔╝██████╔╝██║╚██████╔╝
  ╚═╝  ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝
  ███████╗██╗██╗  ████████╗███████╗██████╗
  ██╔════╝██║██║  ╚══██╔══╝██╔════╝██╔══██╗
  █████╗  ██║██║     ██║   █████╗  ██████╔╝
  ██╔══╝  ██║██║     ██║   ██╔══╝  ██╔══██╗
  ██║     ██║███████╗██║   ███████╗██║  ██║
  ╚═╝     ╚═╝╚══════╝╚═╝   ╚══════╝╚═╝  ╚═╝
       Quality Filter & Speaker Pipeline

An automated tool that goes through a pile of audio and tells you which recordings are clean enough to keep.


1. What it does

You point the pipeline at a folder of audio files or a HuggingFace dataset, and it checks every recording in two stages:

  1. Quality filter — rejects audio that is noisy, clipped, robotic, or bandwidth-limited.
  2. Speaker overlap filter — rejects audio where two or more people talk at the same time.

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.


2. The three models

The pipeline uses three pre-trained models. They are already included in the repo (or downloaded automatically) — you do not train anything.

ModelStageWhat it is for
V1QualityNarrowband audio — sample rate ≤ 24 kHz (phone-quality, older recordings). Extracts 12 acoustic metrics and scores how likely the audio is bad.
V2QualityWideband audio — sample rate > 24 kHz (modern, full-quality recordings). Extracts 34 acoustic metrics, normalizes loudness, then scores it.
PyannoteSpeaker overlapA 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.


3. Install

Prerequisites

  • Linux (Ubuntu / Debian recommended)
  • Python 3.10–3.13 (make install auto-detects a compatible interpreter)
  • make
  • ffmpeg — install with sudo apt-get install ffmpeg

Download and set up

git 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.


4. Run

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:

  • A local folder — the full path to a directory with audio files, e.g. /home/user/my_audio. The pipeline scans it recursively for .wav .mp3 .flac .ogg .opus .m4a files.
  • A HuggingFace dataset — e.g. 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.

Log in to HuggingFace first

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.

All commands

CommandDescription
make installCreate venv/ and install dependencies
make loginAuthenticate with HuggingFace (required — models live on HF)
make runRun the pipeline
make cleanRemove the venv/ directory
make helpShow the command reference

5. What you get

All results are written to the results/ folder (configurable — see §7):

FileWhat is inside
all_filter_results.jsonQuality verdict (good / uncertain / bad) and bad_prob for every file
all_features_full.jsonAll raw acoustic metrics for every file
all_speaker_results.jsonSpeaker-overlap result for every file the quality filter passed
all_filter_metadata.jsonThe final merged file — quality + features + speaker, one record per audio

Quality verdicts

bad_probVerdictMeaning
lowgoodClean audio — keep it
middleuncertainBorderline — review manually
highbadPoor quality — reject

Speaker-overlap verdicts

StatusMeaning
GOODOne speaker — keep it
UNCERTAINPossible overlap — review manually
BADMultiple speakers overlap — reject
TOO_SHORTShorter 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.


6. Tuning the thresholds

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.yamlControlsDefault
quality_filter.v1.good_belowgood upper bound for narrowband audio (V1)0.35
quality_filter.v1.bad_abovebad lower bound for narrowband audio (V1)0.55
quality_filter.v2.good_belowgood upper bound for wideband audio (V2)0.30
quality_filter.v2.bad_abovebad lower bound for wideband audio (V2)0.50
speaker_filter.overlap_thresholdBase speaker-overlap cut-off (auto-adjusted by sample rate)0.25

Raise bad_abovelooser (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 rateLenient boundStrict bound
≤ 24 kHzthreshold − 0.05threshold + 0.05
24–32 kHzmax(threshold, 0.30)max(threshold + 0.10, 0.40)
> 32 kHzmax(threshold, 0.60)max(threshold + 0.20, 0.80)

7. Configuration reference

Everything is in config.yaml. Open it in any text editor — every value has a comment. Below is what each section does.

input — data source

input:
  source: ""                # default answer for the launch prompt
  folder_batch_size: 500    # local-folder mode: audio files processed per batch
KeyDescription
sourceDefault data source. A full folder path or a HuggingFace dataset name. Leave empty ("") to be asked every time.
folder_batch_sizeWhen 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 options

Used 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_filter

quality_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_filter

speaker_filter:
  workers: 8                # parallel CPU processes
  overlap_threshold: 0.25

save_settings

save_settings:
  local: results            # folder for the result JSON files
KeyDescription
localWhere the all_*.json result files are written. Change it to put results elsewhere.

How resuming works

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.


Troubleshooting

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.


Project structure

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

License

This project is licensed under Apache 2.0 — see LICENSE.

Third-party model

The speaker-overlap stage uses a third-party model, downloaded at runtime and not included in this repository:

It is governed by its own license, not by this project's Apache 2.0 license.

Contributors

Arsen2453

13 commits

Languages

Python

89.5%

Makefile

10.5%