Skip to main content

Real-time audio quality assessment for voice apps

Project description

voicequal

Real-time audio quality assessment for voice apps.

Answers the question every voice app eventually has to answer: "is this recording clean enough to process?"

voicequal analyzes audio using four acoustic metrics and returns a tier — excellent, good, fair, or poor — plus the numbers behind the decision.

$ voicequal listen
[15:26:37]  EXCELLENT   room= 45.5 dBA   SNR=18.4dB
[15:26:53]  CHANGE  GOOD   room= 55.0 dBA
[15:26:59]  CHANGE  FAIR   room= 60.4 dBA
[15:27:09]  CHANGE  POOR   room= 71.4 dBA
[15:27:53]  CHANGE  EXCELLENT   room= 45.5 dBA

Install

pip install voicequal              # core library
pip install 'voicequal[mic]'       # + live-mic support

Quick start

Analyze a file

from voicequal import assess

result = assess("recording.wav")
print(result.quality)          # "good"
print(result.background_db)    # 52.3
print(result.snr)              # 24.1
print(result.reason)           # "25<snr<=35 with moderate room: good"

Real-time streaming

from voicequal import LiveDetector

detector = LiveDetector()
detector.on_change(lambda result: print(f"→ {result.quality}"))

while streaming:
    chunk = get_audio_chunk()   # any float32 numpy array
    detector.push(chunk)

Command line

voicequal assess my_recording.wav      # one-shot file report
voicequal listen                       # live mic streaming
voicequal listen --calibrate           # first-time mic calibration
voicequal listen --sensitive           # stricter thresholds

First listen run auto-calibrates the mic (10 seconds — sit quiet then make noise). Calibration is saved to ~/.voicequal/.

How it works

voicequal is built around SNR-gated tiered assessment. The intuition: a loud room only matters if your voice isn't dominant. So SNR gates the loudness penalty before it applies.

SNR > 50 dB          → excellent (voice dominates completely)
SNR 35-50            → excellent unless room > 72 dBA
SNR 25-35            → depends on room loudness
SNR ≤ 25             → composite score across all four metrics

The four metrics feeding this decision:

Metric What it captures
SNR How much louder the peak bin is than the noise floor
Spectral flatness How "noise-like" (chaotic) vs "tonal" (structured) it is
Temporal variance Is noise sustained (fan) or transient (a passing car)
Background dBA Overall room loudness, using minimum statistics tracking

Streaming is stabilized with a hysteresis buffer — a new tier has to persist for 3 frames before it's announced, so single-frame blips don't cause flicker.

Noise floor is estimated with the 10th percentile of recent RMS values (robust to voice bursts, decays when room quiets). Room loudness is reported as the median of recent RMS (tracks sustained noise, ignores single-frame silences).

Limits — read this before using in production

  • voicequal is calibrated for voice / recording quality. Whether a recording is clean enough to process, not whether it sounds subjectively pleasing to a human.
  • Not a certified acoustic dB meter. Background dBA is a calibrated proxy using rough dB conversion, not the IEC 61672 A-weighted filter a real SPL meter uses.
  • Different mics deliver different signal levels. Run voicequal listen --calibrate once per new machine or mic setup.
  • Assumes reasonable audio input. No echo cancellation or noise suppression built in. If your OS pre-processes mic audio (macOS Voice Isolation, browser noise suppression), your calibration will account for it — but detection accuracy will vary.

API reference

assess(path, target_sample_rate=16000, threshold_offset_db=0.0)

Analyze an audio file. Returns a FileAssessment with: quality, reason, background_db, snr, spectral_flatness, temporal_variance, primary_score, secondary_score, total_score, duration_seconds, sample_rate, num_frames.

LiveDetector(sample_rate=16000, stability_frames=3, threshold_offset_db=0.0, db_offset=94.0)

Streaming detector. Methods:

  • push(samples) — append audio (any length, float32 numpy array)
  • on_change(callback) — fire when the stable tier changes
  • get_current() — snapshot the latest LiveAssessment
  • reset() — clear buffers and history

CLI

voicequal --version
voicequal assess <path>
voicequal listen [--calibrate] [--reset-calibration]
                 [--sensitive] [--stability-frames N]
                 [--heartbeat SECONDS]

Development

git clone https://github.com/jiya-singhal/voicequal
cd voicequal
poetry install --extras mic
poetry run pytest -v

70 tests, all under tests/. The library has no runtime dependencies beyond numpy, scipy, soundfile, and rich (CLI). sounddevice is optional (for live-mic support).

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voicequal-0.1.0.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voicequal-0.1.0-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file voicequal-0.1.0.tar.gz.

File metadata

  • Download URL: voicequal-0.1.0.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Darwin/25.5.0

File hashes

Hashes for voicequal-0.1.0.tar.gz
Algorithm Hash digest
SHA256 090061c6b68ad7e01e3c87c31ec6ed32a97c2bdff10376d62267c373fb14cb26
MD5 fa095ce27fa235f83724d641492a94a9
BLAKE2b-256 2a85a511a1b45507fa563abe54aae0578286ea4a0b34db6d75feab914a8d5744

See more details on using hashes here.

File details

Details for the file voicequal-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: voicequal-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.1 CPython/3.14.6 Darwin/25.5.0

File hashes

Hashes for voicequal-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d9977ab274cc02dbb141bf1fd7258fde20db19a0c31aca7a85d385dbaf132f2
MD5 837fb4d6645dc2237a728761a4baef91
BLAKE2b-256 a7f0fbdc8fadc2bd8316249900c30c38e7d148443e062aa7066fb9ddf9032ae1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page