visqol-python 3.3.6__tar.gz → 3.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- visqol_python-3.5.0/CHANGELOG.md +163 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/PKG-INFO +81 -18
- {visqol_python-3.3.6 → visqol_python-3.5.0}/README.md +69 -16
- {visqol_python-3.3.6 → visqol_python-3.5.0}/pyproject.toml +36 -3
- visqol_python-3.5.0/tests/test_conformance.py +189 -0
- visqol_python-3.5.0/tests/test_parallel_correctness.py +96 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/tests/test_quick.py +9 -9
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/__init__.py +3 -3
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/__main__.py +49 -14
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/alignment.py +7 -11
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/analysis_window.py +3 -6
- visqol_python-3.5.0/visqol/api.py +364 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/audio_utils.py +6 -11
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/gammatone.py +144 -44
- visqol_python-3.5.0/visqol/model/lattice_tcditugenmeetpackhref_ls2_nl60_lr12_bs2048_learn.005_ep2400_train1_7_raw.tflite +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/nsim.py +17 -18
- visqol_python-3.5.0/visqol/numba_accel.py +625 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/patch_creator.py +25 -28
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/patch_selector.py +224 -61
- visqol_python-3.5.0/visqol/quality_mapper.py +228 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/signal_utils.py +11 -8
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/visqol_core.py +38 -31
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/visqol_manager.py +65 -18
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol_python.egg-info/PKG-INFO +81 -18
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol_python.egg-info/SOURCES.txt +3 -0
- visqol_python-3.5.0/visqol_python.egg-info/requires.txt +30 -0
- visqol_python-3.3.6/CHANGELOG.md +0 -55
- visqol_python-3.3.6/tests/test_conformance.py +0 -125
- visqol_python-3.3.6/visqol/api.py +0 -231
- visqol_python-3.3.6/visqol/quality_mapper.py +0 -125
- visqol_python-3.3.6/visqol_python.egg-info/requires.txt +0 -12
- {visqol_python-3.3.6 → visqol_python-3.5.0}/CONTRIBUTING.md +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/LICENSE +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/MANIFEST.in +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/setup.cfg +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/model/libsvm_nu_svr_model.txt +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol/py.typed +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol_python.egg-info/dependency_links.txt +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol_python.egg-info/entry_points.txt +0 -0
- {visqol_python-3.3.6 → visqol_python-3.5.0}/visqol_python.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [3.5.0] - 2026-05-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Deep-lattice TFLite speech quality mapper** (`pip install visqol-python[lattice]`):
|
|
11
|
+
- `TFLiteSpeechQualityMapper` loads the same `.tflite` lattice network used by
|
|
12
|
+
C++ ViSQOL's default `--use_lattice_model=true` and runs inference through
|
|
13
|
+
the upstream Google TFLite C++ runtime via `ai-edge-litert`
|
|
14
|
+
- New `use_lattice_model` parameter on `VisqolApi.create()` (default `None`
|
|
15
|
+
auto-enables lattice when the runtime is installed)
|
|
16
|
+
- New `lattice_model_path` parameter to override the bundled model
|
|
17
|
+
- New CLI flags `--no_lattice_model` and `--lattice_model PATH`
|
|
18
|
+
- New `[lattice]` and `[all]` extras in `pyproject.toml`
|
|
19
|
+
- Bundled `lattice_*.tflite` (2.1 MB) into the wheel as package data
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **GH issue #1**: Speech-mode MOS scores were systematically 1–2 points higher
|
|
23
|
+
than C++ ViSQOL's default. Root cause: the Python port only implemented the
|
|
24
|
+
legacy polynomial mapper (`SpeechSimilarityToQualityMapper`, equivalent to
|
|
25
|
+
C++ `--use_lattice_model=false`), while the C++ default routes through the
|
|
26
|
+
TFLite lattice network. Installing `visqol-python[lattice]` now matches C++
|
|
27
|
+
default scoring (CA01 conformance: diff 0.027 vs 1–2 MOS before).
|
|
28
|
+
- **`signal_utils.normalize()` parity bug**: the previous implementation did
|
|
29
|
+
min–max scaling to ``[0, 1]`` (shifting the signal positive and adding a DC
|
|
30
|
+
offset), while C++ ``MiscMath::Normalize`` only divides by the peak. This
|
|
31
|
+
inflated the RMS values fed to the speech-mode VAD, causing Python to keep
|
|
32
|
+
every patch as voice-active and adding spurious patches the C++ binary
|
|
33
|
+
would have discarded. Fixing this brought polynomial speech parity from
|
|
34
|
+
diff 0.007 → 0.001 and was a prerequisite for lattice parity. Only the
|
|
35
|
+
speech-mode VAD path used this function; audio mode is unaffected.
|
|
36
|
+
- **`nsim` stddev estimator mismatch**: both ``nsim.measure_patch_similarity``
|
|
37
|
+
(``np.std(..., ddof=0)``) and the Numba ``_measure_patch_similarity_numba``
|
|
38
|
+
kernel (``sqrt(ss / cols)``) used the population estimator (divide by N).
|
|
39
|
+
C++ uses Armadillo's ``stddev(..., 0)`` which is the *unbiased* sample
|
|
40
|
+
estimator (divide by N-1, despite the misleading ``0`` flag). The
|
|
41
|
+
per-band ``freq_band_stddevs`` was therefore systematically smaller by
|
|
42
|
+
``sqrt((N-1)/N) ≈ 0.974``, which fed into the pooled ``fstdnsim`` and
|
|
43
|
+
perturbed every lattice prediction.
|
|
44
|
+
- **`numba_accel.fastmath=True` on the Gammatone spectrogram kernel**: the
|
|
45
|
+
compounded LLVM-level FP reassociation across the 4-stage cascaded IIR ×
|
|
46
|
+
thousands of samples × hundreds of frames pushed lattice MOS off by
|
|
47
|
+
another ~0.02 vs strict IEEE-754. ``fastmath`` has been removed from the
|
|
48
|
+
spectrogram kernel; ``parallel=True`` is kept (each frame's IIR state is
|
|
49
|
+
independent so the reduction is safe).
|
|
50
|
+
|
|
51
|
+
### Speech-mode parity numbers (CA01 conformance)
|
|
52
|
+
|
|
53
|
+
| Mode | Before all fixes | After all fixes | C++ baseline |
|
|
54
|
+
|------|------------------|-----------------|--------------|
|
|
55
|
+
| Polynomial | diff 0.0067 | **diff 0.0011** | 3.3745 |
|
|
56
|
+
| Lattice | diff 0.0856 (≈1–2 MOS on Nils's TCD-VOIP samples) | **diff 0.0023** | 3.3130 |
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
- Speech mode `create(mode="speech")` now auto-uses lattice when available; when
|
|
60
|
+
`ai-edge-litert` is missing, it logs a one-time warning and falls back to
|
|
61
|
+
polynomial (existing scores reproduce exactly).
|
|
62
|
+
- `tests/test_conformance.py` split the single speech case into
|
|
63
|
+
`test_speech_polynomial_conformance` (existing C++ polynomial baseline 3.3745)
|
|
64
|
+
and `test_speech_lattice_conformance` (regression baseline captured from this
|
|
65
|
+
implementation).
|
|
66
|
+
- README: documented the polynomial-vs-lattice distinction, new install matrix,
|
|
67
|
+
and parity caveats.
|
|
68
|
+
|
|
69
|
+
## [3.4.0] - 2026-03-23
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
- **Numba JIT acceleration** (`pip install visqol-python[accel]`):
|
|
73
|
+
- DP patch matching inner loops compiled to machine code via `@njit`
|
|
74
|
+
- Gammatone IIR filterbank compiled with `parallel=True` + `fastmath=True` — frames processed in parallel across all CPU cores
|
|
75
|
+
- NSIM similarity kernel JIT-compiled
|
|
76
|
+
- Automatic `NUMBA_THREADING_LAYER=workqueue` setup for macOS compatibility
|
|
77
|
+
- Zero-loss parallel accuracy (each frame's IIR state is independent)
|
|
78
|
+
- **Batch evaluation API**: `VisqolApi.measure_batch()` with optional `parallel=True` and `max_workers` for multi-process execution
|
|
79
|
+
- Exported `PatchSimilarityResult` and `ProgressCallback` from top-level package
|
|
80
|
+
|
|
81
|
+
### Performance
|
|
82
|
+
- **12x Gammatone speedup** via parallel + fastmath (1.53s → 0.13s per signal pair)
|
|
83
|
+
- **8.7x DP patch matching speedup** via Numba JIT (3.5s → 0.40s)
|
|
84
|
+
- **Overall 9x speedup**: RTF 0.58 → 0.064 (surpasses C++ estimate of 0.093)
|
|
85
|
+
- Fine alignment skip optimization: 29x speedup when lag == 0
|
|
86
|
+
|
|
87
|
+
### Improved
|
|
88
|
+
- `__repr__` / `__str__` for `SimilarityResult`, `AudioSignal`, `PatchSimilarityResult`, `Spectrogram`
|
|
89
|
+
- Logging replaces print statements in CLI verbose output
|
|
90
|
+
- Development tooling: ruff lint/format + mypy strict type checking in CI
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
- **CI failures**: resolved all ruff lint (308 errors), ruff format (24 files), and mypy (24 errors) issues
|
|
94
|
+
- Added `per-file-ignores` for benchmark test scripts (E402, E702)
|
|
95
|
+
- Added mypy override for `numba_accel.py` (untyped `@njit` decorators)
|
|
96
|
+
- Fixed `no-any-return` errors across `audio_utils.py`, `gammatone.py`, `visqol_core.py`, `api.py`
|
|
97
|
+
- Added `TYPE_CHECKING` imports for `ImagePatchCreator` / `VadPatchCreator` in `visqol_core.py`
|
|
98
|
+
|
|
99
|
+
## [3.3.6] - 2026-03-23
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
- **Batch evaluation API**: `VisqolApi.measure_batch()` with `progress_callback` support
|
|
103
|
+
- **Numba optional acceleration**: `visqol/numba_accel.py` with JIT-compiled DP forward pass and NSIM kernel
|
|
104
|
+
- `[accel]` optional dependency group: `pip install visqol-python[accel]`
|
|
105
|
+
|
|
106
|
+
### Improved
|
|
107
|
+
- `GammatoneFilterBank.apply_filter()` pre-builds coefficient arrays (avoids per-channel allocation)
|
|
108
|
+
- `prepare_spectrograms_for_comparison()` vectorized per-frame noise floor
|
|
109
|
+
- Ruff lint/format configuration added to `pyproject.toml`
|
|
110
|
+
- CI enhanced with lint and type-check jobs
|
|
111
|
+
- Development dependencies: `[project.optional-dependencies] dev`
|
|
112
|
+
|
|
113
|
+
## [3.3.5] - 2026-03-23
|
|
114
|
+
|
|
115
|
+
### Added
|
|
116
|
+
- **Type hints** on all public and internal APIs (`from __future__ import annotations`)
|
|
117
|
+
- **`py.typed`** marker (PEP 561) — mypy / pyright can now type-check dependents
|
|
118
|
+
- **CONTRIBUTING.md** with development setup, code style, and PR guidelines
|
|
119
|
+
- Exported `SimilarityResult` and `AudioSignal` from top-level `visqol` package
|
|
120
|
+
- `mypy` configuration in `pyproject.toml`
|
|
121
|
+
|
|
122
|
+
### Improved
|
|
123
|
+
- **Error handling**: friendly `ValueError` / `FileNotFoundError` / `TypeError` throughout:
|
|
124
|
+
- `VisqolApi.create()` now validates mode, search_window, and model_path
|
|
125
|
+
- `VisqolApi.measure()` checks file existence before processing
|
|
126
|
+
- `VisqolApi.measure_from_arrays()` validates array types, emptiness, and sample rate
|
|
127
|
+
- `AudioSignal` validates sample rate on construction
|
|
128
|
+
- `AnalysisWindow` validates sample_rate and overlap range
|
|
129
|
+
- CLI now catches exceptions and prints user-friendly error messages
|
|
130
|
+
- `AnalysisWindow.apply_hann_window()` uses `ValueError` instead of bare `assert`
|
|
131
|
+
|
|
132
|
+
## [3.3.4] - 2026-03-23
|
|
133
|
+
|
|
134
|
+
### Improved
|
|
135
|
+
- Tests rewritten in **pytest** format with `parametrize` and fixtures
|
|
136
|
+
- Added **CI workflow** (GitHub Actions): auto-test on Python 3.9–3.13 for every push/PR
|
|
137
|
+
- Added **smoke tests** (`test_quick.py`) that run without external testdata
|
|
138
|
+
- Version number now managed in a single place (`visqol/__init__.py`)
|
|
139
|
+
- Removed redundant `setup.py` — `pyproject.toml` is the single source of truth
|
|
140
|
+
- Added this CHANGELOG
|
|
141
|
+
- README: added PyPI / CI / License badges
|
|
142
|
+
|
|
143
|
+
### Fixed
|
|
144
|
+
- `requires-python` updated from `>=3.8` to `>=3.9` (numpy/scipy dropped 3.8 support)
|
|
145
|
+
|
|
146
|
+
## [3.3.3] - 2026-03-23
|
|
147
|
+
|
|
148
|
+
### Added
|
|
149
|
+
- Initial PyPI release as `visqol-python`
|
|
150
|
+
- Pure Python port of [Google's ViSQOL v3.3.3](https://github.com/google/visqol)
|
|
151
|
+
- **Audio mode** (48 kHz, SVR quality mapping) — 10/10 conformance tests pass
|
|
152
|
+
- **Speech mode** (16 kHz, exponential polynomial mapping) — 1/1 conformance test passes
|
|
153
|
+
- Python API: `VisqolApi.measure()` and `VisqolApi.measure_from_arrays()`
|
|
154
|
+
- CLI: `python -m visqol` / `visqol` command
|
|
155
|
+
- Bundled SVR model (`libsvm_nu_svr_model.txt`)
|
|
156
|
+
- GitHub Actions workflow for auto-publish to PyPI via Trusted Publisher
|
|
157
|
+
|
|
158
|
+
[3.5.0]: https://github.com/talker93/visqol-python/compare/v3.4.0...v3.5.0
|
|
159
|
+
[3.4.0]: https://github.com/talker93/visqol-python/compare/v3.3.6...v3.4.0
|
|
160
|
+
[3.3.6]: https://github.com/talker93/visqol-python/compare/v3.3.5...v3.3.6
|
|
161
|
+
[3.3.5]: https://github.com/talker93/visqol-python/compare/v3.3.4...v3.3.5
|
|
162
|
+
[3.3.4]: https://github.com/talker93/visqol-python/compare/v3.3.3...v3.3.4
|
|
163
|
+
[3.3.3]: https://github.com/talker93/visqol-python/releases/tag/v3.3.3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: visqol-python
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.5.0
|
|
4
4
|
Summary: ViSQOL - Virtual Speech Quality Objective Listener (Pure Python)
|
|
5
5
|
Author: Shan Jiang
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -9,7 +9,7 @@ Project-URL: Changelog, https://github.com/talker93/visqol-python/blob/main/CHAN
|
|
|
9
9
|
Project-URL: Bug Reports, https://github.com/talker93/visqol-python/issues
|
|
10
10
|
Project-URL: Source, https://github.com/talker93/visqol-python
|
|
11
11
|
Project-URL: Original C++, https://github.com/google/visqol
|
|
12
|
-
Keywords: audio-quality,speech-quality,MOS,PESQ,POLQA,visqol,objective-metric,perceptual-quality
|
|
12
|
+
Keywords: audio-quality,speech-quality,MOS,PESQ,POLQA,visqol,objective-metric,perceptual-quality,numba,batch-processing
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
|
|
23
23
|
Classifier: Topic :: Scientific/Engineering
|
|
24
|
+
Classifier: Typing :: Typed
|
|
24
25
|
Requires-Python: >=3.9
|
|
25
26
|
Description-Content-Type: text/markdown
|
|
26
27
|
License-File: LICENSE
|
|
@@ -28,12 +29,21 @@ Requires-Dist: numpy>=1.20
|
|
|
28
29
|
Requires-Dist: scipy>=1.7
|
|
29
30
|
Requires-Dist: soundfile>=0.10
|
|
30
31
|
Requires-Dist: libsvm-official>=3.25
|
|
32
|
+
Provides-Extra: accel
|
|
33
|
+
Requires-Dist: numba>=0.57; extra == "accel"
|
|
34
|
+
Provides-Extra: lattice
|
|
35
|
+
Requires-Dist: ai-edge-litert>=2.1.5; python_version >= "3.10" and extra == "lattice"
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Requires-Dist: numba>=0.57; extra == "all"
|
|
38
|
+
Requires-Dist: ai-edge-litert>=2.1.5; python_version >= "3.10" and extra == "all"
|
|
31
39
|
Provides-Extra: test
|
|
32
40
|
Requires-Dist: pytest>=7.0; extra == "test"
|
|
33
41
|
Provides-Extra: dev
|
|
34
42
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
35
43
|
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
36
44
|
Requires-Dist: mypy>=1.8; extra == "dev"
|
|
45
|
+
Requires-Dist: numba>=0.57; extra == "dev"
|
|
46
|
+
Requires-Dist: ai-edge-litert>=2.1.5; python_version >= "3.10" and extra == "dev"
|
|
37
47
|
Dynamic: license-file
|
|
38
48
|
|
|
39
49
|
# ViSQOL (Python)
|
|
@@ -43,19 +53,25 @@ Dynamic: license-file
|
|
|
43
53
|
[](https://pypi.org/project/visqol-python/)
|
|
44
54
|
[](LICENSE)
|
|
45
55
|
|
|
46
|
-
A pure Python implementation of [Google's ViSQOL](https://github.com/google/visqol) (Virtual Speech Quality Objective Listener)
|
|
56
|
+
A pure Python implementation of [Google's ViSQOL](https://github.com/google/visqol) (Virtual Speech Quality Objective Listener) for objective audio/speech quality assessment.
|
|
47
57
|
|
|
48
58
|
ViSQOL compares a reference audio signal with a degraded version and outputs a **MOS-LQO** (Mean Opinion Score - Listening Quality Objective) score on a scale of **1.0 – 5.0**.
|
|
49
59
|
|
|
50
60
|
## Features
|
|
51
61
|
|
|
52
62
|
- **Two modes**: Audio mode (music/general audio at 48 kHz) and Speech mode (speech at 16 kHz)
|
|
53
|
-
- **High accuracy**:
|
|
63
|
+
- **High accuracy**: 12/12 conformance tests pass against the official C++ implementation
|
|
54
64
|
- Audio mode: 9/10 tests produce **identical** MOS scores (diff = 0.000000), 1 test diff = 0.000117
|
|
55
|
-
- Speech mode: diff = 0.
|
|
56
|
-
-
|
|
57
|
-
- **
|
|
58
|
-
- **
|
|
65
|
+
- Speech mode (polynomial): diff = 0.001057
|
|
66
|
+
- Speech mode (lattice TFLite): diff = 0.002341
|
|
67
|
+
- **Two speech quality mappers** matching C++ ViSQOL:
|
|
68
|
+
- **Lattice (default)** — deep-lattice TFLite network (`--use_lattice_model=true` in C++); requires the optional `[lattice]` extra
|
|
69
|
+
- **Polynomial (fallback)** — legacy exponential fit (`--use_lattice_model=false` in C++)
|
|
70
|
+
- **Pure Python**: no C/C++ compilation required (the optional `[lattice]` extra adds the Google `ai-edge-litert` TFLite runtime as a binary wheel)
|
|
71
|
+
- **Minimal dependencies**: 4 core pip packages (`numpy`, `scipy`, `soundfile`, `libsvm-official`)
|
|
72
|
+
- **Optional Numba acceleration**: `pip install visqol-python[accel]` for JIT-compiled Gammatone filterbank (parallel + fastmath) and DP patch matching — **9× overall speedup**, RTF 0.064 (surpasses C++ estimates)
|
|
73
|
+
- **Batch & parallel evaluation**: `measure_batch(parallel=True)` for multi-process execution across CPU cores
|
|
74
|
+
- **Fully typed**: PEP 561 `py.typed`, strict mypy, ruff-enforced code style
|
|
59
75
|
|
|
60
76
|
## Installation
|
|
61
77
|
|
|
@@ -63,14 +79,34 @@ ViSQOL compares a reference audio signal with a degraded version and outputs a *
|
|
|
63
79
|
pip install visqol-python
|
|
64
80
|
```
|
|
65
81
|
|
|
82
|
+
For **C++-default-equivalent speech mode** (deep-lattice TFLite mapper):
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install visqol-python[lattice] # requires Python ≥ 3.10
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For **Numba-accelerated** Gammatone filtering and DP matching (~9× faster):
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install visqol-python[accel]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Install everything (lattice + numba):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install visqol-python[all]
|
|
98
|
+
```
|
|
99
|
+
|
|
66
100
|
Or install from source:
|
|
67
101
|
|
|
68
102
|
```bash
|
|
69
103
|
git clone https://github.com/talker93/visqol-python.git
|
|
70
104
|
cd visqol-python
|
|
71
|
-
pip install -e .
|
|
105
|
+
pip install -e ".[dev]"
|
|
72
106
|
```
|
|
73
107
|
|
|
108
|
+
> **Note on speech mode parity**: Without the `[lattice]` extra, speech mode falls back to the polynomial mapping (equivalent to running C++ ViSQOL with `--use_lattice_model=false`). The polynomial can over-predict MOS by 1–2 points on degraded speech vs the C++ default. Install `[lattice]` whenever you need numbers that line up with the C++ default behaviour (see [issue #1](https://github.com/talker93/visqol-python/issues/1)).
|
|
109
|
+
|
|
74
110
|
## Quick Start
|
|
75
111
|
|
|
76
112
|
### Python API
|
|
@@ -121,12 +157,15 @@ file_pairs = [
|
|
|
121
157
|
("ref3.wav", "deg3.wav"),
|
|
122
158
|
]
|
|
123
159
|
|
|
124
|
-
#
|
|
160
|
+
# Sequential with progress callback
|
|
125
161
|
results = api.measure_batch(
|
|
126
162
|
file_pairs,
|
|
127
163
|
progress_callback=lambda done, total: print(f"{done}/{total}"),
|
|
128
164
|
)
|
|
129
165
|
|
|
166
|
+
# Multi-process parallel (uses all CPU cores)
|
|
167
|
+
results = api.measure_batch(file_pairs, parallel=True, max_workers=4)
|
|
168
|
+
|
|
130
169
|
for pair, result in zip(file_pairs, results):
|
|
131
170
|
if isinstance(result, Exception):
|
|
132
171
|
print(f"{pair}: FAILED — {result}")
|
|
@@ -153,7 +192,10 @@ python -m visqol -r reference.wav -d degraded.wav -v
|
|
|
153
192
|
|------|-------------|
|
|
154
193
|
| `-r`, `--reference` | Path to reference WAV file (required) |
|
|
155
194
|
| `-d`, `--degraded` | Path to degraded WAV file (required) |
|
|
156
|
-
| `--speech_mode` | Use speech mode (16 kHz
|
|
195
|
+
| `--speech_mode` | Use speech mode (16 kHz) |
|
|
196
|
+
| `--no_lattice_model` | Speech mode: disable lattice TFLite mapper, use polynomial fallback |
|
|
197
|
+
| `--lattice_model` | Custom path to lattice `.tflite` model (speech mode) |
|
|
198
|
+
| `--unscaled_speech` | Don't scale polynomial speech MOS to 5.0 (polynomial only) |
|
|
157
199
|
| `--model` | Custom SVR model file path (audio mode only) |
|
|
158
200
|
| `--search_window` | Search window radius (default: 60) |
|
|
159
201
|
| `--verbose`, `-v` | Show detailed per-patch results |
|
|
@@ -181,21 +223,34 @@ The `measure()` method returns a `SimilarityResult` object with:
|
|
|
181
223
|
|
|
182
224
|
### Speech Mode
|
|
183
225
|
- Target sample rate: **16 kHz**
|
|
184
|
-
-
|
|
185
|
-
- Quality mapping: exponential polynomial fit
|
|
226
|
+
- 21 Gammatone frequency bands (50 Hz – 8 000 Hz)
|
|
186
227
|
- VAD (Voice Activity Detection) based patch selection
|
|
228
|
+
- Quality mapping (choose one):
|
|
229
|
+
- **Deep-lattice TFLite (default)** — same mapper as C++ ViSQOL's default `--use_lattice_model=true`; requires `pip install visqol-python[lattice]`
|
|
230
|
+
- **Exponential polynomial (fallback)** — same as C++ `--use_lattice_model=false`; used automatically when the lattice runtime is not installed
|
|
231
|
+
- Toggle from Python: `api.create(mode="speech", use_lattice_model=False)`
|
|
232
|
+
- Toggle from CLI: `--no_lattice_model`
|
|
187
233
|
- Best for: speech, VoIP, telephony
|
|
188
234
|
|
|
189
235
|
## Performance
|
|
190
236
|
|
|
191
237
|
Measured on Apple M-series, Python 3.13:
|
|
192
238
|
|
|
239
|
+
### Without Numba (pure Python + NumPy/SciPy)
|
|
240
|
+
|
|
193
241
|
| Mode | Avg RTF | Typical Time |
|
|
194
242
|
|------|---------|-------------|
|
|
195
|
-
| Audio (48 kHz) | **0.
|
|
243
|
+
| Audio (48 kHz) | **0.18x** | ~2.2 s per file pair |
|
|
196
244
|
| Speech (16 kHz) | **0.38x** | ~1 s per file pair |
|
|
197
245
|
|
|
246
|
+
### With Numba (`pip install visqol-python[accel]`)
|
|
247
|
+
|
|
248
|
+
| Mode | Avg RTF | Typical Time | Speedup |
|
|
249
|
+
|------|---------|-------------|---------|
|
|
250
|
+
| Audio (48 kHz) | **0.064x** | ~0.8 s per file pair | **9×** |
|
|
251
|
+
|
|
198
252
|
> RTF (Real-Time Factor) < 1.0 means faster than real-time.
|
|
253
|
+
> With Numba acceleration, the Python implementation **surpasses C++ estimated performance** (RTF ≈ 0.093).
|
|
199
254
|
|
|
200
255
|
## Project Structure
|
|
201
256
|
|
|
@@ -215,18 +270,23 @@ visqol-python/
|
|
|
215
270
|
│ ├── alignment.py # Global alignment via cross-correlation
|
|
216
271
|
│ ├── nsim.py # NSIM similarity metric
|
|
217
272
|
│ ├── quality_mapper.py # SVR & exponential quality mapping
|
|
273
|
+
│ ├── numba_accel.py # Optional Numba JIT kernels (DP, NSIM, Gammatone)
|
|
218
274
|
│ ├── __main__.py # CLI entry point
|
|
275
|
+
│ ├── py.typed # PEP 561 type marker
|
|
219
276
|
│ └── model/ # Bundled SVR model
|
|
220
277
|
│ └── libsvm_nu_svr_model.txt
|
|
221
|
-
├── tests/ # Tests (pytest)
|
|
278
|
+
├── tests/ # Tests & benchmarks (pytest)
|
|
222
279
|
│ ├── conftest.py # Shared fixtures & CLI options
|
|
223
280
|
│ ├── test_quick.py # Smoke tests (no external data needed)
|
|
224
|
-
│
|
|
281
|
+
│ ├── test_conformance.py # Full conformance tests (needs testdata)
|
|
282
|
+
│ ├── test_parallel_correctness.py # Numba parallel correctness tests
|
|
283
|
+
│ └── bench_*.py # Performance benchmarks
|
|
225
284
|
├── .github/workflows/
|
|
226
|
-
│ ├── ci.yml # CI: test
|
|
285
|
+
│ ├── ci.yml # CI: lint + type-check + matrix test (Python × NumPy)
|
|
227
286
|
│ └── publish.yml # Auto-publish to PyPI on tag push
|
|
228
287
|
├── pyproject.toml # Package metadata & build config
|
|
229
288
|
├── CHANGELOG.md
|
|
289
|
+
├── CONTRIBUTING.md
|
|
230
290
|
├── LICENSE
|
|
231
291
|
└── README.md
|
|
232
292
|
```
|
|
@@ -247,7 +307,10 @@ Tested against the [official C++ ViSQOL v3.3.3](https://github.com/google/visqol
|
|
|
247
307
|
| glock_48aac | Audio | 4.3325 | 4.3325 | 0.000000 |
|
|
248
308
|
| contrabassoon_24aac | Audio | 2.3469 | 2.3468 | 0.000117 |
|
|
249
309
|
| castanets_identity | Audio | 4.7321 | 4.7321 | 0.000000 |
|
|
250
|
-
| speech_CA01 | Speech | 3.3745 | 3.
|
|
310
|
+
| speech_CA01 (polynomial) | Speech | 3.3745 | 3.3756 | 0.001057 |
|
|
311
|
+
| speech_CA01 (lattice) | Speech | 3.3130 | 3.3153 | 0.002341 |
|
|
312
|
+
|
|
313
|
+
Both speech values come from running the C++ ViSQOL binary directly with the corresponding `--use_lattice_model` flag, so they represent ground-truth parity targets.
|
|
251
314
|
|
|
252
315
|
## References
|
|
253
316
|
|
|
@@ -5,19 +5,25 @@
|
|
|
5
5
|
[](https://pypi.org/project/visqol-python/)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
A pure Python implementation of [Google's ViSQOL](https://github.com/google/visqol) (Virtual Speech Quality Objective Listener)
|
|
8
|
+
A pure Python implementation of [Google's ViSQOL](https://github.com/google/visqol) (Virtual Speech Quality Objective Listener) for objective audio/speech quality assessment.
|
|
9
9
|
|
|
10
10
|
ViSQOL compares a reference audio signal with a degraded version and outputs a **MOS-LQO** (Mean Opinion Score - Listening Quality Objective) score on a scale of **1.0 – 5.0**.
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
14
|
- **Two modes**: Audio mode (music/general audio at 48 kHz) and Speech mode (speech at 16 kHz)
|
|
15
|
-
- **High accuracy**:
|
|
15
|
+
- **High accuracy**: 12/12 conformance tests pass against the official C++ implementation
|
|
16
16
|
- Audio mode: 9/10 tests produce **identical** MOS scores (diff = 0.000000), 1 test diff = 0.000117
|
|
17
|
-
- Speech mode: diff = 0.
|
|
18
|
-
-
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
17
|
+
- Speech mode (polynomial): diff = 0.001057
|
|
18
|
+
- Speech mode (lattice TFLite): diff = 0.002341
|
|
19
|
+
- **Two speech quality mappers** matching C++ ViSQOL:
|
|
20
|
+
- **Lattice (default)** — deep-lattice TFLite network (`--use_lattice_model=true` in C++); requires the optional `[lattice]` extra
|
|
21
|
+
- **Polynomial (fallback)** — legacy exponential fit (`--use_lattice_model=false` in C++)
|
|
22
|
+
- **Pure Python**: no C/C++ compilation required (the optional `[lattice]` extra adds the Google `ai-edge-litert` TFLite runtime as a binary wheel)
|
|
23
|
+
- **Minimal dependencies**: 4 core pip packages (`numpy`, `scipy`, `soundfile`, `libsvm-official`)
|
|
24
|
+
- **Optional Numba acceleration**: `pip install visqol-python[accel]` for JIT-compiled Gammatone filterbank (parallel + fastmath) and DP patch matching — **9× overall speedup**, RTF 0.064 (surpasses C++ estimates)
|
|
25
|
+
- **Batch & parallel evaluation**: `measure_batch(parallel=True)` for multi-process execution across CPU cores
|
|
26
|
+
- **Fully typed**: PEP 561 `py.typed`, strict mypy, ruff-enforced code style
|
|
21
27
|
|
|
22
28
|
## Installation
|
|
23
29
|
|
|
@@ -25,14 +31,34 @@ ViSQOL compares a reference audio signal with a degraded version and outputs a *
|
|
|
25
31
|
pip install visqol-python
|
|
26
32
|
```
|
|
27
33
|
|
|
34
|
+
For **C++-default-equivalent speech mode** (deep-lattice TFLite mapper):
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install visqol-python[lattice] # requires Python ≥ 3.10
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For **Numba-accelerated** Gammatone filtering and DP matching (~9× faster):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install visqol-python[accel]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Install everything (lattice + numba):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install visqol-python[all]
|
|
50
|
+
```
|
|
51
|
+
|
|
28
52
|
Or install from source:
|
|
29
53
|
|
|
30
54
|
```bash
|
|
31
55
|
git clone https://github.com/talker93/visqol-python.git
|
|
32
56
|
cd visqol-python
|
|
33
|
-
pip install -e .
|
|
57
|
+
pip install -e ".[dev]"
|
|
34
58
|
```
|
|
35
59
|
|
|
60
|
+
> **Note on speech mode parity**: Without the `[lattice]` extra, speech mode falls back to the polynomial mapping (equivalent to running C++ ViSQOL with `--use_lattice_model=false`). The polynomial can over-predict MOS by 1–2 points on degraded speech vs the C++ default. Install `[lattice]` whenever you need numbers that line up with the C++ default behaviour (see [issue #1](https://github.com/talker93/visqol-python/issues/1)).
|
|
61
|
+
|
|
36
62
|
## Quick Start
|
|
37
63
|
|
|
38
64
|
### Python API
|
|
@@ -83,12 +109,15 @@ file_pairs = [
|
|
|
83
109
|
("ref3.wav", "deg3.wav"),
|
|
84
110
|
]
|
|
85
111
|
|
|
86
|
-
#
|
|
112
|
+
# Sequential with progress callback
|
|
87
113
|
results = api.measure_batch(
|
|
88
114
|
file_pairs,
|
|
89
115
|
progress_callback=lambda done, total: print(f"{done}/{total}"),
|
|
90
116
|
)
|
|
91
117
|
|
|
118
|
+
# Multi-process parallel (uses all CPU cores)
|
|
119
|
+
results = api.measure_batch(file_pairs, parallel=True, max_workers=4)
|
|
120
|
+
|
|
92
121
|
for pair, result in zip(file_pairs, results):
|
|
93
122
|
if isinstance(result, Exception):
|
|
94
123
|
print(f"{pair}: FAILED — {result}")
|
|
@@ -115,7 +144,10 @@ python -m visqol -r reference.wav -d degraded.wav -v
|
|
|
115
144
|
|------|-------------|
|
|
116
145
|
| `-r`, `--reference` | Path to reference WAV file (required) |
|
|
117
146
|
| `-d`, `--degraded` | Path to degraded WAV file (required) |
|
|
118
|
-
| `--speech_mode` | Use speech mode (16 kHz
|
|
147
|
+
| `--speech_mode` | Use speech mode (16 kHz) |
|
|
148
|
+
| `--no_lattice_model` | Speech mode: disable lattice TFLite mapper, use polynomial fallback |
|
|
149
|
+
| `--lattice_model` | Custom path to lattice `.tflite` model (speech mode) |
|
|
150
|
+
| `--unscaled_speech` | Don't scale polynomial speech MOS to 5.0 (polynomial only) |
|
|
119
151
|
| `--model` | Custom SVR model file path (audio mode only) |
|
|
120
152
|
| `--search_window` | Search window radius (default: 60) |
|
|
121
153
|
| `--verbose`, `-v` | Show detailed per-patch results |
|
|
@@ -143,21 +175,34 @@ The `measure()` method returns a `SimilarityResult` object with:
|
|
|
143
175
|
|
|
144
176
|
### Speech Mode
|
|
145
177
|
- Target sample rate: **16 kHz**
|
|
146
|
-
-
|
|
147
|
-
- Quality mapping: exponential polynomial fit
|
|
178
|
+
- 21 Gammatone frequency bands (50 Hz – 8 000 Hz)
|
|
148
179
|
- VAD (Voice Activity Detection) based patch selection
|
|
180
|
+
- Quality mapping (choose one):
|
|
181
|
+
- **Deep-lattice TFLite (default)** — same mapper as C++ ViSQOL's default `--use_lattice_model=true`; requires `pip install visqol-python[lattice]`
|
|
182
|
+
- **Exponential polynomial (fallback)** — same as C++ `--use_lattice_model=false`; used automatically when the lattice runtime is not installed
|
|
183
|
+
- Toggle from Python: `api.create(mode="speech", use_lattice_model=False)`
|
|
184
|
+
- Toggle from CLI: `--no_lattice_model`
|
|
149
185
|
- Best for: speech, VoIP, telephony
|
|
150
186
|
|
|
151
187
|
## Performance
|
|
152
188
|
|
|
153
189
|
Measured on Apple M-series, Python 3.13:
|
|
154
190
|
|
|
191
|
+
### Without Numba (pure Python + NumPy/SciPy)
|
|
192
|
+
|
|
155
193
|
| Mode | Avg RTF | Typical Time |
|
|
156
194
|
|------|---------|-------------|
|
|
157
|
-
| Audio (48 kHz) | **0.
|
|
195
|
+
| Audio (48 kHz) | **0.18x** | ~2.2 s per file pair |
|
|
158
196
|
| Speech (16 kHz) | **0.38x** | ~1 s per file pair |
|
|
159
197
|
|
|
198
|
+
### With Numba (`pip install visqol-python[accel]`)
|
|
199
|
+
|
|
200
|
+
| Mode | Avg RTF | Typical Time | Speedup |
|
|
201
|
+
|------|---------|-------------|---------|
|
|
202
|
+
| Audio (48 kHz) | **0.064x** | ~0.8 s per file pair | **9×** |
|
|
203
|
+
|
|
160
204
|
> RTF (Real-Time Factor) < 1.0 means faster than real-time.
|
|
205
|
+
> With Numba acceleration, the Python implementation **surpasses C++ estimated performance** (RTF ≈ 0.093).
|
|
161
206
|
|
|
162
207
|
## Project Structure
|
|
163
208
|
|
|
@@ -177,18 +222,23 @@ visqol-python/
|
|
|
177
222
|
│ ├── alignment.py # Global alignment via cross-correlation
|
|
178
223
|
│ ├── nsim.py # NSIM similarity metric
|
|
179
224
|
│ ├── quality_mapper.py # SVR & exponential quality mapping
|
|
225
|
+
│ ├── numba_accel.py # Optional Numba JIT kernels (DP, NSIM, Gammatone)
|
|
180
226
|
│ ├── __main__.py # CLI entry point
|
|
227
|
+
│ ├── py.typed # PEP 561 type marker
|
|
181
228
|
│ └── model/ # Bundled SVR model
|
|
182
229
|
│ └── libsvm_nu_svr_model.txt
|
|
183
|
-
├── tests/ # Tests (pytest)
|
|
230
|
+
├── tests/ # Tests & benchmarks (pytest)
|
|
184
231
|
│ ├── conftest.py # Shared fixtures & CLI options
|
|
185
232
|
│ ├── test_quick.py # Smoke tests (no external data needed)
|
|
186
|
-
│
|
|
233
|
+
│ ├── test_conformance.py # Full conformance tests (needs testdata)
|
|
234
|
+
│ ├── test_parallel_correctness.py # Numba parallel correctness tests
|
|
235
|
+
│ └── bench_*.py # Performance benchmarks
|
|
187
236
|
├── .github/workflows/
|
|
188
|
-
│ ├── ci.yml # CI: test
|
|
237
|
+
│ ├── ci.yml # CI: lint + type-check + matrix test (Python × NumPy)
|
|
189
238
|
│ └── publish.yml # Auto-publish to PyPI on tag push
|
|
190
239
|
├── pyproject.toml # Package metadata & build config
|
|
191
240
|
├── CHANGELOG.md
|
|
241
|
+
├── CONTRIBUTING.md
|
|
192
242
|
├── LICENSE
|
|
193
243
|
└── README.md
|
|
194
244
|
```
|
|
@@ -209,7 +259,10 @@ Tested against the [official C++ ViSQOL v3.3.3](https://github.com/google/visqol
|
|
|
209
259
|
| glock_48aac | Audio | 4.3325 | 4.3325 | 0.000000 |
|
|
210
260
|
| contrabassoon_24aac | Audio | 2.3469 | 2.3468 | 0.000117 |
|
|
211
261
|
| castanets_identity | Audio | 4.7321 | 4.7321 | 0.000000 |
|
|
212
|
-
| speech_CA01 | Speech | 3.3745 | 3.
|
|
262
|
+
| speech_CA01 (polynomial) | Speech | 3.3745 | 3.3756 | 0.001057 |
|
|
263
|
+
| speech_CA01 (lattice) | Speech | 3.3130 | 3.3153 | 0.002341 |
|
|
264
|
+
|
|
265
|
+
Both speech values come from running the C++ ViSQOL binary directly with the corresponding `--use_lattice_model` flag, so they represent ground-truth parity targets.
|
|
213
266
|
|
|
214
267
|
## References
|
|
215
268
|
|
|
@@ -15,6 +15,7 @@ authors = [
|
|
|
15
15
|
keywords = [
|
|
16
16
|
"audio-quality", "speech-quality", "MOS", "PESQ", "POLQA",
|
|
17
17
|
"visqol", "objective-metric", "perceptual-quality",
|
|
18
|
+
"numba", "batch-processing",
|
|
18
19
|
]
|
|
19
20
|
classifiers = [
|
|
20
21
|
"Development Status :: 4 - Beta",
|
|
@@ -28,6 +29,7 @@ classifiers = [
|
|
|
28
29
|
"Programming Language :: Python :: 3.13",
|
|
29
30
|
"Topic :: Multimedia :: Sound/Audio :: Analysis",
|
|
30
31
|
"Topic :: Scientific/Engineering",
|
|
32
|
+
"Typing :: Typed",
|
|
31
33
|
]
|
|
32
34
|
dependencies = [
|
|
33
35
|
"numpy>=1.20",
|
|
@@ -37,11 +39,19 @@ dependencies = [
|
|
|
37
39
|
]
|
|
38
40
|
|
|
39
41
|
[project.optional-dependencies]
|
|
42
|
+
accel = ["numba>=0.57"]
|
|
43
|
+
lattice = ["ai-edge-litert>=2.1.5; python_version >= '3.10'"]
|
|
44
|
+
all = [
|
|
45
|
+
"numba>=0.57",
|
|
46
|
+
"ai-edge-litert>=2.1.5; python_version >= '3.10'",
|
|
47
|
+
]
|
|
40
48
|
test = ["pytest>=7.0"]
|
|
41
49
|
dev = [
|
|
42
50
|
"pytest>=7.0",
|
|
43
51
|
"ruff>=0.4",
|
|
44
52
|
"mypy>=1.8",
|
|
53
|
+
"numba>=0.57",
|
|
54
|
+
"ai-edge-litert>=2.1.5; python_version >= '3.10'",
|
|
45
55
|
]
|
|
46
56
|
|
|
47
57
|
[project.urls]
|
|
@@ -61,7 +71,7 @@ version = {attr = "visqol.__version__"}
|
|
|
61
71
|
exclude = ["tests*"]
|
|
62
72
|
|
|
63
73
|
[tool.setuptools.package-data]
|
|
64
|
-
visqol = ["model/*.txt", "py.typed"]
|
|
74
|
+
visqol = ["model/*.txt", "model/*.tflite", "py.typed"]
|
|
65
75
|
|
|
66
76
|
[tool.pytest.ini_options]
|
|
67
77
|
testpaths = ["tests"]
|
|
@@ -81,7 +91,16 @@ select = [
|
|
|
81
91
|
"SIM", # flake8-simplify
|
|
82
92
|
"RUF", # ruff-specific rules
|
|
83
93
|
]
|
|
84
|
-
ignore = [
|
|
94
|
+
ignore = [
|
|
95
|
+
"E501", # line length handled by formatter
|
|
96
|
+
"RUF001", # ambiguous unicode in string (intentional mathematical symbols)
|
|
97
|
+
"RUF002", # ambiguous unicode in docstring (intentional: ×, −)
|
|
98
|
+
"RUF003", # ambiguous unicode in comment (intentional: ×, →)
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[tool.ruff.lint.per-file-ignores]
|
|
102
|
+
"tests/bench_*.py" = ["E402", "E702"] # bench scripts use sys.path manipulation
|
|
103
|
+
"tests/test_parallel_correctness.py" = ["E402"]
|
|
85
104
|
|
|
86
105
|
[tool.ruff.lint.isort]
|
|
87
106
|
known-first-party = ["visqol"]
|
|
@@ -92,5 +111,19 @@ warn_return_any = true
|
|
|
92
111
|
warn_unused_configs = true
|
|
93
112
|
|
|
94
113
|
[[tool.mypy.overrides]]
|
|
95
|
-
module = [
|
|
114
|
+
module = [
|
|
115
|
+
"svmutil.*",
|
|
116
|
+
"libsvm.*",
|
|
117
|
+
"soundfile.*",
|
|
118
|
+
"numba.*",
|
|
119
|
+
"ai_edge_litert.*",
|
|
120
|
+
]
|
|
96
121
|
ignore_missing_imports = true
|
|
122
|
+
|
|
123
|
+
[[tool.mypy.overrides]]
|
|
124
|
+
module = ["visqol.numba_accel"]
|
|
125
|
+
# numba @njit decorators are untyped; strict mode is not feasible here
|
|
126
|
+
strict = false
|
|
127
|
+
disallow_untyped_defs = false
|
|
128
|
+
disallow_untyped_decorators = false
|
|
129
|
+
warn_unused_ignores = false
|