Skip to content
cccskills
FreePublished on GitHub

audiogear

Annotate speech/TTS datasets with per-clip quality metrics (MOS, SNR, STOI, pitch, bandwidth, speaking rate, WER/CER, gender/emotion), multi-ASR consensus transcription and speaker labeling using the audiogear pipeline; then filter clips by quality and build listenable HTML QA reports. Use when asked to compute audio dataset metrics, build extended_metadata.csv, transcribe unlabeled audio, select clean TTS training data, or QA a speech dataset.

The English summary is being prepared. Showing the original description.

Works withLINE
See how to install

Files included (109)

  • SKILL.md9.7 KB
  • .env.example360 B
  • .gitignore872 B
  • configs/annotate.yaml3.0 KB
  • configs/config.yaml693 B
  • configs/executor/local.yaml730 B
  • configs/metric/bandwidth.yaml192 B
  • configs/metric/brouhaha_snr_reverb.yaml217 B
  • configs/metric/distillmos.yaml136 B
  • configs/metric/emotion.yaml153 B
  • configs/metric/gender.yaml124 B
  • configs/metric/gigaam_multilingual.yaml743 B
  • configs/metric/gigaam_v3.yaml844 B
  • configs/metric/pitch.yaml631 B
  • configs/metric/speaker.yaml256 B
  • configs/metric/speaking_rate.yaml177 B
  • configs/metric/squim.yaml134 B
  • configs/metric/style.yaml129 B
  • configs/metric/wada_snr.yaml108 B
  • configs/metric/wer.yaml201 B
  • configs/reader/csv.yaml376 B
  • configs/reader/folder.yaml256 B
  • configs/reader/ru.yaml440 B
  • configs/resd.yaml2.8 KB
  • configs/writer/csv.yaml123 B
  • configs/writer/jsonl.yaml120 B
  • docs/multi-node.md3.6 KB
  • docs/README.md641 B
  • docs/storage.md4.1 KB
  • docs/testing.md5.3 KB
  • eval/sanity_distillmos.py3.0 KB
  • examples/filter_clean.py4.4 KB
  • examples/gen_configs.py6.1 KB
  • examples/qa_report.py12.9 KB
  • examples/README.md2.3 KB
  • examples/run_batch.py4.4 KB
  • LICENSE1.1 KB
  • process.py931 B
  • pyproject.toml4.3 KB
  • README.md28.5 KB
  • src/audiogear/__init__.py847 B
  • src/audiogear/audio.py3.7 KB
  • src/audiogear/build.py4.6 KB
  • src/audiogear/data.py1.2 KB
  • src/audiogear/executer/__init__.py0 B
  • src/audiogear/executer/base.py5.7 KB
  • src/audiogear/executer/local.py6.3 KB
  • src/audiogear/io.py9.2 KB
  • src/audiogear/pipeline/__init__.py0 B
  • src/audiogear/pipeline/base.py2.2 KB
  • src/audiogear/pipeline/checkpoint.py3.2 KB
  • src/audiogear/pipeline/metrics/__init__.py0 B
  • src/audiogear/pipeline/metrics/accent.py1.6 KB
  • src/audiogear/pipeline/metrics/bandwidth.py2.3 KB
  • src/audiogear/pipeline/metrics/base.py25.9 KB
  • src/audiogear/pipeline/metrics/brouhaha_snr_reverb.py2.3 KB
  • src/audiogear/pipeline/metrics/distillmos.py2.1 KB
  • src/audiogear/pipeline/metrics/emotion.py1.3 KB
  • src/audiogear/pipeline/metrics/gender.py1.3 KB
  • src/audiogear/pipeline/metrics/gigaam_v3.py6.9 KB
  • src/audiogear/pipeline/metrics/hf.py7.9 KB
  • src/audiogear/pipeline/metrics/models/__init__.py0 B
  • src/audiogear/pipeline/metrics/models/brouhaha_vad.py12.1 KB
  • src/audiogear/pipeline/metrics/models/nisqa/__init__.py0 B
  • src/audiogear/pipeline/metrics/pitch.py6.0 KB
  • src/audiogear/pipeline/metrics/punctuation.py5.9 KB
  • src/audiogear/pipeline/metrics/speaker.py11.6 KB
  • src/audiogear/pipeline/metrics/speaking_rate.py4.6 KB
  • src/audiogear/pipeline/metrics/squim.py2.5 KB
  • src/audiogear/pipeline/metrics/style.py2.1 KB
  • src/audiogear/pipeline/metrics/wada_snr.py4.0 KB
  • src/audiogear/pipeline/metrics/wav2vec_mos.py1.3 KB
  • src/audiogear/pipeline/metrics/wer.py3.5 KB
  • src/audiogear/pipeline/parallel.py5.2 KB
  • src/audiogear/pipeline/readers/__init__.py27 B
  • src/audiogear/pipeline/readers/base.py6.1 KB
  • src/audiogear/pipeline/readers/csv.py3.3 KB
  • src/audiogear/pipeline/readers/folder.py3.9 KB
  • src/audiogear/pipeline/readers/huggingface.py2.8 KB
  • src/audiogear/pipeline/readers/jsonl.py1.9 KB
  • src/audiogear/pipeline/segmenters/__init__.py0 B
  • src/audiogear/pipeline/segmenters/base.py3.7 KB
  • src/audiogear/pipeline/segmenters/whisper.py5.5 KB
  • src/audiogear/pipeline/transcribers/__init__.py415 B
  • src/audiogear/pipeline/transcribers/backends.py4.9 KB
  • src/audiogear/pipeline/transcribers/base.py1.6 KB
  • src/audiogear/pipeline/transcribers/consensus.py6.9 KB
  • src/audiogear/pipeline/writers/__init__.py0 B
  • src/audiogear/pipeline/writers/base_disk.py3.5 KB
  • src/audiogear/pipeline/writers/csv.py4.3 KB
  • src/audiogear/pipeline/writers/jsonl.py708 B
  • src/audiogear/utils/__init__.py0 B
  • src/audiogear/utils/import_utils.py479 B
  • src/audiogear/utils/logging.py1.6 KB
  • src/audiogear/utils/progress.py1.3 KB
  • src/audiogear/utils/runtime.py6.5 KB
  • tests/conftest.py831 B
  • tests/test_checkpoint_resume.py4.7 KB
  • tests/test_csv_roundtrip.py1.4 KB
  • tests/test_csv_writer.py5.5 KB
  • tests/test_merge_dedup.py1.9 KB
  • tests/test_metric_columns.py912 B
  • tests/test_metric_guard.py6.0 KB
  • tests/test_metric_scheduling.py2.7 KB
  • tests/test_progress.py1.3 KB
  • tests/test_punct_transfer.py4.1 KB
  • tests/test_reader_adapter.py1.6 KB
  • tests/test_runtime.py3.2 KB
  • tests/test_wer_normalize.py748 B

SKILL.md (original)

Review the instructions the agent will receive before you install.

audiogear — speech-dataset annotation pipeline

audiogear (https://github.com/lIkesimba9/audiogear) computes per-clip features over a speech dataset: reader → metric blocks → CSV writer, configured with Hydra, sharded across GPUs/nodes. This skill drives it from any project.

Copy this file into the consuming project as .claude/skills/audiogear/SKILL.md. Set AUDIOGEAR_HOME below to wherever the audiogear checkout lives.

Setup (once per machine)

export AUDIOGEAR_HOME=~/audiogear            # adjust; add to the project env
git clone https://github.com/lIkesimba9/audiogear.git "$AUDIOGEAR_HOME" || true
cd "$AUDIOGEAR_HOME"
uv sync --extra ru-pipeline                  # or à-la-carte: --extra mos --extra asr --extra pitch
sudo apt-get install -y espeak-ng            # needed only for SpeakingRateMetric
cp -n .env.example .env                      # put HF_TOKEN= in .env for gated models (pyannote)

Python 3.10–3.12. GigaAM pins torch <2.6 — do not "upgrade" torch inside this venv.

Input contract

One directory per dataset with a |-delimited metadata.csv:

<data_root>/<dataset>/
  metadata.csv        # one row per clip
  audio/...           # referenced by audio_path, relative to the dataset dir

Required columns: id (unique), audio_path, text (may be empty). All other columns pass through untouched; computed metric columns are appended. If the source data has a different shape, first write a converter that produces this layout (see build_betterset-style scripts) — do NOT teach audiogear the foreign schema.

Core workflow

1. Write a dataset config

Create $AUDIOGEAR_HOME/configs/feat_<ds>.yaml. Proven template (mirrors the generated feat_* configs) with CPU∥GPU lanes so DSP metrics hide under GPU time:

defaults:
  - reader: ru          # CsvReader preset: delimiter "|", audio_key=audio_path, id_key=id
  - writer: csv
  - executor: local
  - _self_
hydra:
  job: {chdir: false}
  run: {dir: .}
  output_subdir: null
device: cuda
reader:
  data_folder: /path/to/data_root/<ds>
  glob_pattern: metadata.csv
  limit: -1             # set to 10 for a dry run
writer:
  output_folder: outputs/<ds>
  output_filename: ext_$rank.csv
  sep: "|"
executor:
  tasks: 8              # shards; rows are split round-robin
  workers: 2            # concurrent processes; each pins ONE GPU (rank % gpus)
  skip_completed: true
  logging_dir: logs/<ds>
metrics:
  - _target_: audiogear.pipeline.parallel.ParallelLanes
    lanes:
      cpu:
        - _target_: audiogear.pipeline.metrics.bandwidth.BandwidthMetric
        - _target_: audiogear.pipeline.metrics.wada_snr.SnrMetric
        - _target_: audiogear.pipeline.metrics.speaking_rate.SpeakingRateMetric
          language: ru
      gpu:
        - _target_: audiogear.pipeline.metrics.distillmos.DistillMosMetric
          device: ${device}
        - _target_: audiogear.pipeline.metrics.squim.SquimMetrics
          device: ${device}
        - _target_: audiogear.pipeline.metrics.pitch.CrepePitchMetric
          device: ${device}
          crepe_model: tiny
        - _target_: audiogear.pipeline.metrics.style.StyleMetric   # after pitch (reuses pitch_*)
        - _target_: audiogear.pipeline.metrics.gender.GenderMetric
          device: ${device}

Add WhisperWer to the gpu lane only when text is human-authored.

Lane rules (violating them corrupts data silently):

  • lanes must write disjoint columns;
  • a metric that consumes another's output (StyleMetric ← pitch_mean, WhisperWer/SpeakingRateMetric ← text) goes in the SAME lane, after its producer; a producer needed by both lanes (e.g. ConsensusTranscriber) runs as an ordinary step BEFORE the lanes block.

2. Dry run, then full run

cd "$AUDIOGEAR_HOME"
uv run python process.py --config-name feat_<ds> reader.limit=10   # smoke test, downloads models
uv run python process.py --config-name feat_<ds>                   # full run

Multi-GPU: executor.workers=<n_gpus>. executor.gpus is an int (count), never a list. Never set CUDA_VISIBLE_DEVICES yourself — the executor pins it. Multi-node: launch the same command once per node under SLURM, or set AUDIOGEAR_NODE_RANK/AUDIOGEAR_NUM_NODES; put executor.logging_dir on shared storage.

3. Merge shards → extended_metadata.csv

Each shard writes outputs/<ds>/ext_<rank>.csv. Merge with id-dedup (duplicates appear if executor.tasks changed between an interrupted run and its rerun):

export AUDIOGEAR_DATA_DIR=/path/to/data_root
uv run python examples/run_batch.py <ds>     # run + merge + .FEAT_DONE marker per dataset

For many datasets, examples/gen_configs.py generates the per-dataset configs and examples/run_batch.py sweeps them smallest-first with resume.

4. Filter + QA

uv run python examples/filter_clean.py <ds>   # extended_metadata.csv -> clean_metadata.csv + drop reasons
uv run python examples/qa_report.py <ds>      # -> <data_root>/<ds>/qa_report.html

qa_report.html is self-contained: metric histograms with the filter thresholds drawn in, and playable audio just below/just above each threshold. To calibrate thresholds: listen to both sides — rejected clips sounding fine ⇒ threshold too strict; accepted clips sounding bad ⇒ too loose. Edit TH in examples/filter_clean.py (single source of truth for filter and report) and regenerate. Set HUMAN_TEXT/ASR_TEXT there: the CER filter is only valid where text was written by humans, not by an ASR model.

Metric catalogue

Class (audiogear.pipeline.metrics.*)ColumnsNotes
distillmos.DistillMosMetricdistillmosno-ref MOS, GPU
squim.SquimMetricspyt_stoi, pyt_pesq, pyt_si_sdrGPU, never batched (padding skews scores)
wada_snr.SnrMetricwada_snrblind SNR, CPU
bandwidth.BandwidthMetricbandwidth_hz, is_upsampled_estdetects upsampled audio; container sample_rate lies
pitch.CrepePitchMetric / pitch.PitchMetricpitch_mean, pitch_stdGPU torchcrepe / CPU pyin
style.StyleMetricenergy_db, energy_dynamics, expressivenessCPU; reuses pitch_* if present
speaking_rate.SpeakingRateMetricspeaking_rate, phonemes_per_word, char_rateespeak-ng; NOT thread-safe — leave it serial
wer.WhisperWerwhisper_wer, whisper_cervs text; -1 when no reference. Skip for ASR-derived text (CER≈0, meaningless, expensive)
gigaam_v3.GigaAMv3gigaam3_text, gigaam3_cer, text_punctuated, opt-in words JSONpunctuated-from-audio RU transcript + punctuation transferred onto reference words; model_name: multilingual_ctc for ru/en/kk/ky/uz (no punctuation — set punct_column: null); words_column adds word timestamps
gender.GenderMetric / emotion.EmotionMetricgender_pred / emotion_pred, emotion_score_pred suffix — never overwrite curated columns
hf.HFAudioModelMetricconfigurableany 🤗 audio classification/regression model, config-only
brouhaha_snr_reverb.SnrReverbMetricssnr, c50pyannote, gated (HF_TOKEN)
speaker.SpeakerLabelerspeaker, speaker_conf, speaker_margindataset-level clustering — run with executor.tasks=1
transcribers.consensus.ConsensusTranscribertext, asr_text_*, asr_agreementmulti-ASR medoid; for datasets without transcripts

Reliability semantics (what to expect downstream)

  • Sentinels, not crashes. A corrupt/unscorable clip never kills a run: the per-clip guard writes NaN (or -1 for WER/CER/SQUIM) and continues. Always treat NaN and negative metric values as "no value" when filtering. A long unbroken failure streak (default 50) aborts the shard — that means a systematic problem (model/config), not bad data.
  • Resume is two-level. Completed shards are skipped via markers in logging_dir; inside an unfinished shard, per-metric JSONL checkpoints in <output_folder>/checkpoints/ resume from the last computed clip. Rerunning the same command after any crash is always safe. Checkpoints are keyed by clip id only — after changing a metric's model/parameters, delete <output_folder>/checkpoints/ (or the run reuses stale values). Disable with resume: false in the config.

Pitfalls checklist

  • executor.gpus: 1 (int) — gpus: [0] breaks.
  • Whisper compute_type: int8_float16 when 2 workers share a GPU (halves VRAM).
  • Clips >25 s are truncated by GigaAMv3; SQUIM needs ≥1024 samples (else -1).
  • Audio must be locally readable (torchaudio); CSVs/outputs/logs may be s3://… (fsspec), audio may not — FUSE-mount buckets instead.
  • Models load lazily per worker process — first clips are slow, that's normal.
  • Adding a metric: subclass BaseMetric, implement compute_metric(segment), set metric= to the column name(s). Do NOT add try/except around it — the base class guards every path already. Load models lazily via audiogear.utils.runtime.cached_model.

Programmatic use (no CLI)

from omegaconf import OmegaConf
from audiogear.build import build_pipeline

cfg = OmegaConf.create({...})       # same shape as a yaml config
data = None
for step in build_pipeline(cfg):    # reader -> metrics -> writer
    data = step(data, 0, 1)         # (data, rank, world_size)
# data: list[AudioSegment]; computed values in segment.metadata

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

Report a problem with this skill