speequal
Speech/audio quality metrics as prebuilt Python wheels — pip install speequal. One metric today:
speequal.visqol — ViSQOL v3, Google's objective, full-reference perceptual audio/speech quality metric (MOS-LQO), plus a small numpy API. This is a packaging of Google's code, not a reimplementation: the C++ library, the pybind11 bindings, the SVR and TFLite lattice models and all default mappings are the ones in google/visqol at the commit recorded in UPSTREAM.md, built with Bazel and redistributed under the same Apache-2.0 license (see LICENSE, NOTICE). Upstream is not on PyPI (the name is prohibited there) and needs Bazel plus a TensorFlow Lite source build to install; this wheel needs neither.
pip install speequal
Wheels: Linux x86_64, CPython 3.12 and 3.14, tagged manylinux_2_39 (built on Ubuntu 24.04 with GCC 13; they need glibc ≥ 2.39 and a GCC-13-era libstdc++). Other platforms/interpreters fall back to the sdist, which needs Bazel (see below). Runtime dependencies: numpy, protobuf (≥ 4.21 — the bindings use message_factory.GetMessageClass; tested with 6.33 and 7.36).
API
from speequal import visqol
visqol.speech(ref, deg, fs=16000) # MOS-LQO, speech mode (wideband, 16 kHz)
visqol.audio(ref, deg, fs=48000) # MOS-LQO, audio mode (SVR model, 48 kHz)
visqol.measure(ref, deg, mode="speech", fs=16000) # upstream's raw SimilarityResultMsg
visqol.selftest() # the install gate (see below); speequal.selftest() runs every metric's
ref / deg are 1-d float arrays (numpy or torch, any float dtype, values in [-1, 1]) or paths to 16-bit PCM WAV files. speech() raises unless fs == 16000 and audio() unless fs == 48000 — nothing is resampled for you; get to the right rate first. Lengths may differ (ViSQOL aligns and handles the mismatch itself; nothing is padded or cropped here). Model files are located inside the package, never relative to the working directory. speequal.__version__ is the wheel version (<upstream visqol version>.postN), speequal.visqol.UPSTREAM_COMMIT the vendored git sha.
Options, all mirroring VisqolConfig fields: speech(..., lattice=True) maps NSIM→MOS with the TFLite deep-lattice model (upstream's binary default; its ceiling for an identical pair is ≈ 4.51), lattice=False uses the scaled polynomial mapping (identical pair → 5.0); unscaled_mos_mapping=True (requires lattice=False, as upstream ignores it otherwise) leaves a perfect score at ≈ 4.0. measure() additionally exposes allow_unsupported_sample_rates and search_window_radius, and returns moslqo, vnsim, fvnsim, fvnsim10, fstdnsim, fvdegenergy, center_freq_bands, patch_sims, alignment_lag_s.
Upstream's own modules are untouched and still importable, one level down: from speequal.visqol import visqol_lib_py, from speequal.visqol.pb2 import visqol_config_pb2, similarity_result_pb2.
CLI
python -m speequal.visqol ref.wav deg.wav # speech mode, prints the MOS-LQO
python -m speequal.visqol ref.wav deg.wav --audio # audio mode
python -m speequal.visqol ref.wav deg.wav --verbose # + VNSIM, per-band NSIM, patch count
The sample rate is read from the files (any rate in speech mode, 48 kHz in audio mode, like upstream's binary). --no-lattice, --unscaled, --allow-unsupported-sample-rates as above.
Self-test
python -c "import speequal; speequal.selftest()"
For ViSQOL: (a) speech mode at 16 kHz: a clip vs itself hits the mapper ceiling (≈ 4.5 lattice / 5.0 polynomial) and a −20 dB-noise copy scores lower; (b) audio mode at 48 kHz: a clip vs itself ≥ 4.7; (c) conformance: the 20 reference/degraded/flag cases of upstream's tests/conformance_test.cc with the expected MOS-LQO values of src/include/conformance.h (copied into speequal/visqol/conformance.json) reproduce to 1e-3. The two clean-speech clips ship in the wheel; the other conformance WAVs (~55 MB) are downloaded once from google/visqol at the pinned commit into ~/.cache/visqol/ (VISQOL_TESTDATA=/path/to/upstream/testdata uses a local copy). visqol.selftest(conformance=False) skips the download.
Building from source
The sdist on PyPI is upstream's tree plus the wrapper; pip install from it runs upstream's setup.py, which needs Bazel 5.3.2 (bazelisk picks it up from .bazelversion), a C++17 compiler, and fetches TensorFlow 2.11 sources — so on an unsupported platform expect a long first build. From this repository:
git clone https://github.com/danjacobellis/speequal && cd speequal
pip install numpy setuptools wheel auditwheel patchelf build # in the target interpreter
./build.sh # installs bazelisk into ~/.local/bin if absent; wheel lands in dist/
./build.sh --python=/path/to/other/python # e.g. a 3.14
./install_for_debugging.sh # build + install into ~/g + selftest
build.sh copies upstream/ to build/upstream/, applies patches/, runs Bazel there, builds the wheel with upstream's setup.py, then auditwheel repairs it to the most specific manylinux policy the build host allows. Bazel's cache makes rebuilds fast; --clean expunges it.
What changed vs upstream
Nothing in the metric. Every deviation from google/visqol is a file in patches/:
0001-bazelrc-gcc13-cstdint.patch—build --cxxopt=-include --cxxopt=cstdint: TF 2.11'stensorflow/lite/kernels/internal/spectrogram.ccusesuint32_twithout including<cstdint>, which GCC 13 no longer tolerates.0002-setup-py-version-wrapper-metadata.patch—setup.py: distributionspeequal, version3.3.3.postN, Google'svisqolpackage mapped tospeequal.visqol(.model,.pb2beneath it), PyPI metadata (readme, license,python_requires,install_requires = numpy, protobuf), aDistribution.has_ext_modulesoverride so the wheel is taggedcpXY-<platform>instead ofpy3-none-any, and copying the wrapper (python_wrapper/) plus the two clean-speech WAVs into the package.0003-workspace-pybind11_protobuf-getmessageclass.patch—WORKSPACEapplies a one-hunk patch to the pinnedpybind11_protobuf(2022): protobuf ≥ 5 removedMessageFactory.GetPrototype, which made every proto conversion silently fail; usemessage_factory.GetMessageClasswhen it exists.0004-manifest-in-sdist.patch—MANIFEST.inso the sdist carries the whole Bazel tree (src/,python/,model/,WORKSPACE,BUILD,.bazelrc,.bazelversion, the patches) and never a previous build'sbazel-bin.
Added on top (not patches): the speequal package from src/speequal/ (__init__.py, visqol/{__init__,api,__main__,selftest}.py, visqol/conformance.json).
Metadata
Release files for speequal 3.3.3.post1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| speequal-3.3.3.post1.tar.gz | 1.4 MB | Without provenance | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| speequal-3.3.3.post1-cp314-cp314-manylinux_2_39_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.39+ x86-64 | Details |
| speequal-3.3.3.post1-cp312-cp312-manylinux_2_39_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.39+ x86-64 | Details |
Total release size: 11.6 MB
Release files / speequal-3.3.3.post1.tar.gz
| Download URL | speequal-3.3.3.post1.tar.gz |
|---|---|
| Size | 1.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fed6e592a1c4eb8f462d34ae62467ae540452d9875aa8050be5fc6969a98d795
|
|
BLAKE2b-256 checksum How to use checksums |
c9463f62572fcf8fa5312fd44fee6da1544ed05d49845de2dae3d2d40a430d4e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Release files / speequal-3.3.3.post1-cp314-cp314-manylinux_2_39_x86_64.whl
| Download URL | speequal-3.3.3.post1-cp314-cp314-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 5.1 MB |
| Tags | CPython 3.14 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
ba53bc72512a11f0cdbaf5fb9e4f28166d16086a043e4a4df91efc7c30151ff5
|
|
BLAKE2b-256 checksum How to use checksums |
15212e7989ea9f20d69bff209287e4f4554ed7f6dbd1a929b619a7e690ff8bd7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Release files / speequal-3.3.3.post1-cp312-cp312-manylinux_2_39_x86_64.whl
| Download URL | speequal-3.3.3.post1-cp312-cp312-manylinux_2_39_x86_64.whl |
|---|---|
| Size | 5.1 MB |
| Tags | CPython 3.12 Linux glibc 2.39+ x86-64 |
|
SHA-256 checksum How to use checksums |
edaaf864018c7751dc6571ca874eeb4b2de1b4ec39cfbcb87871d27c8df28fb9
|
|
BLAKE2b-256 checksum How to use checksums |
b18f8e09f9853db6ecbf9d8c0d8f617e9d195d14226082fa7570cd613045d450
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.3
|
Security for speequal 3.3.3.post1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.