cascadevad-onnx 0.1.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.
Files changed (64) hide show
  1. cascadevad_onnx-0.1.0/CHANGELOG.md +17 -0
  2. cascadevad_onnx-0.1.0/LICENSE +17 -0
  3. cascadevad_onnx-0.1.0/MANIFEST.in +5 -0
  4. cascadevad_onnx-0.1.0/NOTICE +14 -0
  5. cascadevad_onnx-0.1.0/PKG-INFO +135 -0
  6. cascadevad_onnx-0.1.0/README.md +81 -0
  7. cascadevad_onnx-0.1.0/cascadevad/__init__.py +36 -0
  8. cascadevad_onnx-0.1.0/cascadevad/api.py +109 -0
  9. cascadevad_onnx-0.1.0/cascadevad/audio.py +107 -0
  10. cascadevad_onnx-0.1.0/cascadevad/backends/__init__.py +8 -0
  11. cascadevad_onnx-0.1.0/cascadevad/backends/fsmn.py +157 -0
  12. cascadevad_onnx-0.1.0/cascadevad/backends/marblenet.py +113 -0
  13. cascadevad_onnx-0.1.0/cascadevad/backends/pyannote.py +122 -0
  14. cascadevad_onnx-0.1.0/cascadevad/backends/speechbrain.py +105 -0
  15. cascadevad_onnx-0.1.0/cascadevad/backends/ten.py +126 -0
  16. cascadevad_onnx-0.1.0/cascadevad/base.py +186 -0
  17. cascadevad_onnx-0.1.0/cascadevad/cascade.py +379 -0
  18. cascadevad_onnx-0.1.0/cascadevad/cli.py +80 -0
  19. cascadevad_onnx-0.1.0/cascadevad/convert/__init__.py +10 -0
  20. cascadevad_onnx-0.1.0/cascadevad/convert/common.py +155 -0
  21. cascadevad_onnx-0.1.0/cascadevad/convert/fsmn.py +80 -0
  22. cascadevad_onnx-0.1.0/cascadevad/convert/marblenet.py +85 -0
  23. cascadevad_onnx-0.1.0/cascadevad/convert/pyannote.py +54 -0
  24. cascadevad_onnx-0.1.0/cascadevad/convert/silero.py +56 -0
  25. cascadevad_onnx-0.1.0/cascadevad/convert/speechbrain.py +94 -0
  26. cascadevad_onnx-0.1.0/cascadevad/convert/ten.py +72 -0
  27. cascadevad_onnx-0.1.0/cascadevad/data/fsmn_cmvn.npz +0 -0
  28. cascadevad_onnx-0.1.0/cascadevad/data/marblenet_mel_fb.npy +0 -0
  29. cascadevad_onnx-0.1.0/cascadevad/data/marblenet_window.npy +0 -0
  30. cascadevad_onnx-0.1.0/cascadevad/data/sb_vad_mel_fb.npy +0 -0
  31. cascadevad_onnx-0.1.0/cascadevad/data/sb_vad_window.npy +0 -0
  32. cascadevad_onnx-0.1.0/cascadevad/data/silero_vad.onnx +0 -0
  33. cascadevad_onnx-0.1.0/cascadevad/data/ten_vad_coeff.npz +0 -0
  34. cascadevad_onnx-0.1.0/cascadevad/features.py +126 -0
  35. cascadevad_onnx-0.1.0/cascadevad/onnx_backend.py +136 -0
  36. cascadevad_onnx-0.1.0/cascadevad/registry.py +287 -0
  37. cascadevad_onnx-0.1.0/cascadevad/resolver.py +98 -0
  38. cascadevad_onnx-0.1.0/cascadevad/segment.py +129 -0
  39. cascadevad_onnx-0.1.0/cascadevad/signature.py +104 -0
  40. cascadevad_onnx-0.1.0/cascadevad/version.py +12 -0
  41. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/PKG-INFO +135 -0
  42. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/SOURCES.txt +62 -0
  43. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/dependency_links.txt +1 -0
  44. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/entry_points.txt +2 -0
  45. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/requires.txt +36 -0
  46. cascadevad_onnx-0.1.0/cascadevad_onnx.egg-info/top_level.txt +1 -0
  47. cascadevad_onnx-0.1.0/pyproject.toml +64 -0
  48. cascadevad_onnx-0.1.0/setup.cfg +4 -0
  49. cascadevad_onnx-0.1.0/setup.py +6 -0
  50. cascadevad_onnx-0.1.0/test/resources/README.md +13 -0
  51. cascadevad_onnx-0.1.0/test/resources/speech.wav +0 -0
  52. cascadevad_onnx-0.1.0/test/test_api.py +102 -0
  53. cascadevad_onnx-0.1.0/test/test_audio.py +54 -0
  54. cascadevad_onnx-0.1.0/test/test_backends.py +60 -0
  55. cascadevad_onnx-0.1.0/test/test_cascade.py +155 -0
  56. cascadevad_onnx-0.1.0/test/test_cli.py +35 -0
  57. cascadevad_onnx-0.1.0/test/test_custom_onnx.py +54 -0
  58. cascadevad_onnx-0.1.0/test/test_download.py +40 -0
  59. cascadevad_onnx-0.1.0/test/test_features.py +35 -0
  60. cascadevad_onnx-0.1.0/test/test_internals.py +76 -0
  61. cascadevad_onnx-0.1.0/test/test_registry.py +78 -0
  62. cascadevad_onnx-0.1.0/test/test_resolver.py +50 -0
  63. cascadevad_onnx-0.1.0/test/test_segment.py +68 -0
  64. cascadevad_onnx-0.1.0/test/test_signature.py +47 -0
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ Initial release of **cascadevad**, a derivative work of
6
+ [vadonnx](https://github.com/TigreGotico/vadonnx) (© TigreGótico Lda, Apache-2.0).
7
+
8
+ - Renamed the package to `cascadevad`.
9
+ - Added the cost-adaptive **confidence-gated cascade** (`cascadevad.cascade`): a cheap gate
10
+ VAD runs on every frame and a strong expert VAD is invoked only where it would change the
11
+ decision, with pluggable routing, an admission-control SLA, calibration, and a fused
12
+ cost-adaptive ensemble.
13
+ - Re-hosted the ONNX model mirror at
14
+ [`aryashah00/cascadevad-models`](https://huggingface.co/aryashah00/cascadevad-models)
15
+ (one subfolder per model).
16
+ - Unified multi-backend VAD serving over ONNX Runtime (Silero, MarbleNet, pyannote, FSMN,
17
+ SpeechBrain, TEN) inherited from the upstream project.
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 TigreGóticoLda
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include cascadevad/data *.onnx *.json *.npz *.npy
5
+ recursive-include test/resources *
@@ -0,0 +1,14 @@
1
+ cascadevad
2
+ Copyright 2026 aistra
3
+
4
+ This product is a derivative work of "vadonnx"
5
+ Copyright 2026 TigreGótico Lda (https://github.com/TigreGotico/vadonnx),
6
+ licensed under the Apache License, Version 2.0 (see LICENSE).
7
+
8
+ Modifications by aistra (Arya Shah <arya.shah@aistra.com>): renamed the package to
9
+ cascadevad, added the cost-adaptive confidence-gated cascade (cascadevad/cascade.py),
10
+ and re-hosted the ONNX model mirror at https://huggingface.co/aryashah00/cascadevad-models.
11
+
12
+ Bundled and downloaded VAD model weights retain their respective upstream licenses
13
+ (Silero, NVIDIA NeMo Frame-VAD/MarbleNet, pyannote segmentation-3.0, FunASR FSMN,
14
+ SpeechBrain, TEN). See docs/licensing.md for per-model license terms.
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: cascadevad-onnx
3
+ Version: 0.1.0
4
+ Summary: Load arbitrary Voice Activity Detection (VAD) models behind a unified ONNX API
5
+ Author-email: Arya Shah <arya.shah@aistra.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/arya-aistra/cascadevad
8
+ Project-URL: Repository, https://github.com/arya-aistra/cascadevad
9
+ Project-URL: Models, https://huggingface.co/aryashah00/cascadevad-models
10
+ Keywords: vad,voice activity detection,onnx,speech,silero,audio
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
20
+ Classifier: Intended Audience :: Developers
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ License-File: NOTICE
25
+ Requires-Dist: numpy
26
+ Requires-Dist: onnxruntime>=1.17
27
+ Requires-Dist: huggingface_hub
28
+ Provides-Extra: fsmn
29
+ Requires-Dist: kaldi-native-fbank; extra == "fsmn"
30
+ Provides-Extra: mic
31
+ Requires-Dist: sounddevice; extra == "mic"
32
+ Provides-Extra: resample
33
+ Requires-Dist: scipy; extra == "resample"
34
+ Provides-Extra: all
35
+ Requires-Dist: kaldi-native-fbank; extra == "all"
36
+ Requires-Dist: sounddevice; extra == "all"
37
+ Requires-Dist: scipy; extra == "all"
38
+ Provides-Extra: test
39
+ Requires-Dist: pytest; extra == "test"
40
+ Requires-Dist: pytest-cov; extra == "test"
41
+ Provides-Extra: convert
42
+ Requires-Dist: onnx; extra == "convert"
43
+ Requires-Dist: huggingface_hub; extra == "convert"
44
+ Requires-Dist: requests; extra == "convert"
45
+ Provides-Extra: convert-marblenet
46
+ Requires-Dist: cascadevad-onnx[convert]; extra == "convert-marblenet"
47
+ Requires-Dist: nemo_toolkit[asr]; extra == "convert-marblenet"
48
+ Requires-Dist: torch; extra == "convert-marblenet"
49
+ Provides-Extra: convert-speechbrain
50
+ Requires-Dist: cascadevad-onnx[convert]; extra == "convert-speechbrain"
51
+ Requires-Dist: speechbrain; extra == "convert-speechbrain"
52
+ Requires-Dist: torch; extra == "convert-speechbrain"
53
+ Dynamic: license-file
54
+
55
+ # cascadevad
56
+
57
+ Load arbitrary **Voice Activity Detection** models behind a single, unified API — every
58
+ model runs through [ONNX Runtime](https://onnxruntime.ai/). One streaming/​batch
59
+ interface, one audio-format story, pluggable models.
60
+
61
+ ```python
62
+ from cascadevad import load_vad
63
+
64
+ vad = load_vad("silero") # bundled, works fully offline
65
+ prob = vad.process_chunk(pcm_bytes) # streaming → float in [0, 1]
66
+ segments = vad.get_speech_segments(audio, sample_rate=16000)
67
+ # -> [SpeechSegment(start=0.32, end=2.27), SpeechSegment(start=3.27, end=4.45), ...]
68
+ ```
69
+
70
+ ## Why
71
+
72
+ Every VAD ships its own loader, audio format, feature pipeline and state handling.
73
+ `cascadevad` hides that behind one `VADModel` interface: feed it audio (raw `int16`
74
+ bytes, numpy arrays, any sample rate) and get back per-frame speech probabilities or
75
+ ready-made speech segments. Models are described *declaratively* by an
76
+ [`IOSignature`](docs/custom_models.md), so a single generic engine drives most of them
77
+ and you can point the same API at any custom `.onnx` file.
78
+
79
+ - **Lightweight runtime** — only `numpy`, `onnxruntime`, `huggingface_hub`.
80
+ - **Offline by default** — a small Silero model is bundled in the wheel.
81
+ - **Streaming and batch** — `process_chunk()` for live audio, `get_speech_segments()` /
82
+ `probabilities()` for whole buffers.
83
+ - **Bring your own model** — load any ONNX VAD by path/URL with a signature.
84
+ - **Extensible** — third parties register backends/models via entry points.
85
+
86
+ ## Install
87
+
88
+ ```bash
89
+ uv pip install cascadevad-onnx # runtime (numpy + onnxruntime + huggingface_hub)
90
+ uv pip install "cascadevad-onnx[mic]" # + microphone examples
91
+ ```
92
+
93
+ ## Models
94
+
95
+ | name | rate | parity vs upstream | notes |
96
+ |------|------|--------------------|-------|
97
+ | `silero` / `silero-8k` / `silero-op15` | 16k / 8k / 16k | MAE 0 | bundled default, raw PCM |
98
+ | `marblenet` / `marblenet-int8` | 16k | MAE 4e-4 | NVIDIA NeMo Frame-VAD, multilingual ([license](docs/licensing.md)) |
99
+ | `pyannote` / `pyannote-int8` | 16k | MAE 0 | pyannote segmentation-3.0, windowed |
100
+ | `fsmn` / `fsmn-quant` | 16k | tracks upstream | FunASR FSMN-VAD; needs `cascadevad-onnx[fsmn]` |
101
+ | `speechbrain` | 16k | MAE 0 | SpeechBrain CRDNN, LibriParty-trained |
102
+ | `ten` | 16k | — | feature extractor provided by TEN's native library |
103
+
104
+ See [docs/backends.md](docs/backends.md) for per-model detail and the
105
+ [benchmark](benchmark/results/REPORT.md) for measured comparisons across datasets,
106
+ including WebRTC and energy baselines.
107
+
108
+ Models other than the bundled Silero are downloaded on first use from the
109
+ [`aryashah00/cascadevad-models`](https://huggingface.co/aryashah00/cascadevad-models) HuggingFace
110
+ repo and cached under `$XDG_DATA_HOME/cascadevad`. See [docs/backends.md](docs/backends.md) for
111
+ per-model detail and parity notes.
112
+
113
+ ## CLI
114
+
115
+ ```bash
116
+ cascadevad list # list available models
117
+ cascadevad probe silero # print a model's ONNX input/output signature
118
+ cascadevad segment speech.wav # print detected speech segments of a WAV
119
+ ```
120
+
121
+ ## Documentation
122
+
123
+ - [Quickstart](docs/quickstart.md)
124
+ - [Streaming](docs/streaming.md)
125
+ - [Custom models & `IOSignature`](docs/custom_models.md)
126
+ - [Backends & parity notes](docs/backends.md)
127
+ - [Plugins](docs/plugins.md)
128
+ - [Model conversion](docs/conversion.md)
129
+ - [Licensing](docs/licensing.md)
130
+ - [API reference](docs/api.md)
131
+
132
+ ## License
133
+
134
+ Apache-2.0. Bundled/downloaded model weights retain their upstream licenses — see
135
+ [docs/licensing.md](docs/licensing.md).
@@ -0,0 +1,81 @@
1
+ # cascadevad
2
+
3
+ Load arbitrary **Voice Activity Detection** models behind a single, unified API — every
4
+ model runs through [ONNX Runtime](https://onnxruntime.ai/). One streaming/​batch
5
+ interface, one audio-format story, pluggable models.
6
+
7
+ ```python
8
+ from cascadevad import load_vad
9
+
10
+ vad = load_vad("silero") # bundled, works fully offline
11
+ prob = vad.process_chunk(pcm_bytes) # streaming → float in [0, 1]
12
+ segments = vad.get_speech_segments(audio, sample_rate=16000)
13
+ # -> [SpeechSegment(start=0.32, end=2.27), SpeechSegment(start=3.27, end=4.45), ...]
14
+ ```
15
+
16
+ ## Why
17
+
18
+ Every VAD ships its own loader, audio format, feature pipeline and state handling.
19
+ `cascadevad` hides that behind one `VADModel` interface: feed it audio (raw `int16`
20
+ bytes, numpy arrays, any sample rate) and get back per-frame speech probabilities or
21
+ ready-made speech segments. Models are described *declaratively* by an
22
+ [`IOSignature`](docs/custom_models.md), so a single generic engine drives most of them
23
+ and you can point the same API at any custom `.onnx` file.
24
+
25
+ - **Lightweight runtime** — only `numpy`, `onnxruntime`, `huggingface_hub`.
26
+ - **Offline by default** — a small Silero model is bundled in the wheel.
27
+ - **Streaming and batch** — `process_chunk()` for live audio, `get_speech_segments()` /
28
+ `probabilities()` for whole buffers.
29
+ - **Bring your own model** — load any ONNX VAD by path/URL with a signature.
30
+ - **Extensible** — third parties register backends/models via entry points.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ uv pip install cascadevad-onnx # runtime (numpy + onnxruntime + huggingface_hub)
36
+ uv pip install "cascadevad-onnx[mic]" # + microphone examples
37
+ ```
38
+
39
+ ## Models
40
+
41
+ | name | rate | parity vs upstream | notes |
42
+ |------|------|--------------------|-------|
43
+ | `silero` / `silero-8k` / `silero-op15` | 16k / 8k / 16k | MAE 0 | bundled default, raw PCM |
44
+ | `marblenet` / `marblenet-int8` | 16k | MAE 4e-4 | NVIDIA NeMo Frame-VAD, multilingual ([license](docs/licensing.md)) |
45
+ | `pyannote` / `pyannote-int8` | 16k | MAE 0 | pyannote segmentation-3.0, windowed |
46
+ | `fsmn` / `fsmn-quant` | 16k | tracks upstream | FunASR FSMN-VAD; needs `cascadevad-onnx[fsmn]` |
47
+ | `speechbrain` | 16k | MAE 0 | SpeechBrain CRDNN, LibriParty-trained |
48
+ | `ten` | 16k | — | feature extractor provided by TEN's native library |
49
+
50
+ See [docs/backends.md](docs/backends.md) for per-model detail and the
51
+ [benchmark](benchmark/results/REPORT.md) for measured comparisons across datasets,
52
+ including WebRTC and energy baselines.
53
+
54
+ Models other than the bundled Silero are downloaded on first use from the
55
+ [`aryashah00/cascadevad-models`](https://huggingface.co/aryashah00/cascadevad-models) HuggingFace
56
+ repo and cached under `$XDG_DATA_HOME/cascadevad`. See [docs/backends.md](docs/backends.md) for
57
+ per-model detail and parity notes.
58
+
59
+ ## CLI
60
+
61
+ ```bash
62
+ cascadevad list # list available models
63
+ cascadevad probe silero # print a model's ONNX input/output signature
64
+ cascadevad segment speech.wav # print detected speech segments of a WAV
65
+ ```
66
+
67
+ ## Documentation
68
+
69
+ - [Quickstart](docs/quickstart.md)
70
+ - [Streaming](docs/streaming.md)
71
+ - [Custom models & `IOSignature`](docs/custom_models.md)
72
+ - [Backends & parity notes](docs/backends.md)
73
+ - [Plugins](docs/plugins.md)
74
+ - [Model conversion](docs/conversion.md)
75
+ - [Licensing](docs/licensing.md)
76
+ - [API reference](docs/api.md)
77
+
78
+ ## License
79
+
80
+ Apache-2.0. Bundled/downloaded model weights retain their upstream licenses — see
81
+ [docs/licensing.md](docs/licensing.md).
@@ -0,0 +1,36 @@
1
+ """cascadevad — load arbitrary Voice Activity Detection models behind a unified ONNX API.
2
+
3
+ Quick start::
4
+
5
+ from cascadevad import load_vad
6
+
7
+ vad = load_vad("silero") # bundled, works offline
8
+ prob = vad.process_chunk(pcm_bytes) # streaming, float in [0, 1]
9
+ segments = vad.get_speech_segments(audio, sample_rate=16000)
10
+ """
11
+ from .api import list_models, load_vad, register_model
12
+ from .base import VADModel
13
+ from .cascade import (
14
+ AdmissionController,
15
+ CascadeVAD,
16
+ UncertaintyBandRouter,
17
+ )
18
+ from .registry import ModelSpec
19
+ from .segment import SpeechSegment, probs_to_segments
20
+ from .signature import IOSignature
21
+ from .version import __version__
22
+
23
+ __all__ = [
24
+ "load_vad",
25
+ "list_models",
26
+ "register_model",
27
+ "VADModel",
28
+ "CascadeVAD",
29
+ "UncertaintyBandRouter",
30
+ "AdmissionController",
31
+ "IOSignature",
32
+ "ModelSpec",
33
+ "SpeechSegment",
34
+ "probs_to_segments",
35
+ "__version__",
36
+ ]
@@ -0,0 +1,109 @@
1
+ """Public entry points: :func:`load_vad`, :func:`list_models`, :func:`register_model`."""
2
+ from __future__ import annotations
3
+
4
+ from typing import List, Optional, Union
5
+
6
+ from .base import VADModel
7
+ from .registry import (
8
+ ModelSpec,
9
+ get_backend,
10
+ get_spec,
11
+ list_models,
12
+ register_model,
13
+ )
14
+ from .resolver import (
15
+ download_url,
16
+ is_onnx_path,
17
+ is_url,
18
+ resolve_spec_file,
19
+ sidecar_signature,
20
+ )
21
+ from .signature import IOSignature, coerce_signature
22
+
23
+ __all__ = ["load_vad", "list_models", "register_model"]
24
+
25
+
26
+ def load_vad(
27
+ name: str = "silero",
28
+ *,
29
+ signature: Union[IOSignature, dict, None] = None,
30
+ threshold: Optional[float] = None,
31
+ neg_threshold: Optional[float] = None,
32
+ providers: Optional[List[str]] = None,
33
+ intra_threads: int = 1,
34
+ inter_threads: int = 1,
35
+ revision: Optional[str] = None,
36
+ cache_dir: Optional[str] = None,
37
+ **backend_kwargs,
38
+ ) -> VADModel:
39
+ """Load a VAD model behind the unified :class:`~cascadevad.base.VADModel` API.
40
+
41
+ ``name`` may be a built-in/registered/plugin model name (e.g. ``"silero"``,
42
+ ``"ten"``, ``"fsmn"``, ``"marblenet"``), a local ``.onnx`` path, or an
43
+ ``http(s)://`` URL. For an arbitrary custom ONNX file, pass ``signature`` (an
44
+ :class:`IOSignature` or dict) describing its IO; if omitted, a
45
+ ``<model>.signature.json`` sidecar is used when present.
46
+
47
+ Args:
48
+ name: model name, ``.onnx`` path, or URL.
49
+ signature: required for custom ONNX without a sidecar; ignored for known models
50
+ unless you want to override the registry signature.
51
+ threshold: activation threshold for speech. When omitted, each backend's own
52
+ default applies (0.5 for most models, 0.7 for ``speechbrain``).
53
+ neg_threshold: deactivation threshold (defaults to ``threshold - 0.15``).
54
+ providers: ONNX Runtime execution providers (default CPU).
55
+ intra_threads / inter_threads: ORT threading (default 1 each, low latency).
56
+ revision: pin a HuggingFace revision (overrides the registry default).
57
+ cache_dir: override the download cache directory.
58
+ **backend_kwargs: forwarded to the backend constructor.
59
+
60
+ Returns:
61
+ A ready-to-use :class:`~cascadevad.base.VADModel`.
62
+ """
63
+ sig = coerce_signature(signature)
64
+
65
+ # common backend kwargs; pass threshold only when given so each backend keeps its
66
+ # own default otherwise.
67
+ common = dict(providers=providers, intra_threads=intra_threads,
68
+ inter_threads=inter_threads, neg_threshold=neg_threshold,
69
+ **backend_kwargs)
70
+ if threshold is not None:
71
+ common["threshold"] = threshold
72
+
73
+ # 1. explicit local .onnx file
74
+ if is_onnx_path(name) and not is_url(name):
75
+ import os
76
+
77
+ if not os.path.isfile(name):
78
+ raise FileNotFoundError(f"no such ONNX file: {name}")
79
+ sig = sig or sidecar_signature(name)
80
+ if sig is None:
81
+ raise ValueError(
82
+ f"loading a raw .onnx ({name}) requires a `signature` "
83
+ "or a <model>.signature.json sidecar"
84
+ )
85
+ from .onnx_backend import OnnxVAD
86
+
87
+ return OnnxVAD(name, sig, **common)
88
+
89
+ # 2. URL
90
+ if is_url(name):
91
+ path = download_url(name, cache_dir)
92
+ sig = sig or sidecar_signature(path)
93
+ if sig is None:
94
+ raise ValueError("loading a URL model requires a `signature`")
95
+ from .onnx_backend import OnnxVAD
96
+
97
+ return OnnxVAD(path, sig, **common)
98
+
99
+ # 3. registry name
100
+ spec: Optional[ModelSpec] = get_spec(name)
101
+ if spec is None:
102
+ raise KeyError(
103
+ f"unknown model {name!r}; known: {list_models()} "
104
+ "(or pass a .onnx path / URL with a signature)"
105
+ )
106
+ path = resolve_spec_file(spec, revision, cache_dir)
107
+ sig = sig or spec.signature
108
+ backend_cls = get_backend(spec.backend)
109
+ return backend_cls(path, sig, **common)
@@ -0,0 +1,107 @@
1
+ """Audio normalization, resampling and WAV reading helpers (numpy-only core).
2
+
3
+ Everything in :mod:`cascadevad` works internally with mono ``float32`` PCM in the range
4
+ ``[-1, 1]``. These helpers convert the various shapes users pass in (raw ``int16``
5
+ bytes, numpy int/float arrays, stereo) into that canonical form and resample between
6
+ sample rates.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import wave
11
+ from typing import Tuple, Union
12
+
13
+ import numpy as np
14
+
15
+ AudioLike = Union[bytes, bytearray, memoryview, np.ndarray]
16
+
17
+
18
+ def to_float32_mono(audio: AudioLike) -> np.ndarray:
19
+ """Convert audio of various dtypes/containers to mono float32 in [-1, 1].
20
+
21
+ Accepts raw little-endian ``int16`` PCM bytes, or a numpy array of dtype
22
+ ``int16`` / ``int32`` / ``float32`` / ``float64``. Multi-channel arrays
23
+ (shape ``(n, channels)``) are downmixed by averaging channels.
24
+ """
25
+ if isinstance(audio, (bytes, bytearray, memoryview)):
26
+ arr = np.frombuffer(bytes(audio), dtype="<i2").astype(np.float32) / 32768.0
27
+ return arr
28
+
29
+ if not isinstance(audio, np.ndarray):
30
+ raise TypeError(
31
+ f"audio must be bytes or np.ndarray, got {type(audio).__name__}"
32
+ )
33
+
34
+ arr = audio
35
+ # downmix to mono
36
+ if arr.ndim == 2:
37
+ arr = arr.mean(axis=1)
38
+ elif arr.ndim > 2:
39
+ raise ValueError(f"audio array must be 1-D or 2-D, got {arr.ndim}-D")
40
+
41
+ if arr.dtype == np.float32:
42
+ out = arr
43
+ elif arr.dtype == np.float64:
44
+ out = arr.astype(np.float32)
45
+ elif arr.dtype == np.int16:
46
+ out = arr.astype(np.float32) / 32768.0
47
+ elif arr.dtype == np.int32:
48
+ out = arr.astype(np.float32) / 2147483648.0
49
+ elif arr.dtype == np.uint8: # unsigned 8-bit PCM, midpoint 128
50
+ out = (arr.astype(np.float32) - 128.0) / 128.0
51
+ else:
52
+ raise TypeError(f"unsupported audio dtype: {arr.dtype}")
53
+
54
+ return np.ascontiguousarray(out, dtype=np.float32)
55
+
56
+
57
+ def resample(x: np.ndarray, src_sr: int, dst_sr: int) -> np.ndarray:
58
+ """Resample mono float32 audio from ``src_sr`` to ``dst_sr``.
59
+
60
+ Uses ``scipy.signal.resample_poly`` when SciPy is installed (the ``[resample]``
61
+ extra), otherwise falls back to linear interpolation via :func:`numpy.interp`,
62
+ which is adequate for voice activity detection framing.
63
+ """
64
+ if src_sr == dst_sr or x.size == 0:
65
+ return x.astype(np.float32, copy=False)
66
+
67
+ try:
68
+ from scipy.signal import resample_poly # type: ignore
69
+
70
+ from math import gcd
71
+
72
+ g = gcd(int(src_sr), int(dst_sr))
73
+ up, down = int(dst_sr) // g, int(src_sr) // g
74
+ return resample_poly(x, up, down).astype(np.float32)
75
+ except Exception:
76
+ # linear interpolation fallback (no extra deps)
77
+ n_out = int(round(x.shape[0] * dst_sr / src_sr))
78
+ if n_out <= 0:
79
+ return np.zeros(0, dtype=np.float32)
80
+ src_idx = np.linspace(0.0, x.shape[0] - 1, num=n_out, dtype=np.float64)
81
+ return np.interp(src_idx, np.arange(x.shape[0]), x).astype(np.float32)
82
+
83
+
84
+ def read_wav(path: str) -> Tuple[np.ndarray, int]:
85
+ """Read a PCM WAV file into mono float32 audio. Returns ``(audio, sample_rate)``.
86
+
87
+ Uses the standard-library :mod:`wave` module so no third-party audio dependency
88
+ is required for examples and tests.
89
+ """
90
+ with wave.open(path, "rb") as wf:
91
+ sr = wf.getframerate()
92
+ n_channels = wf.getnchannels()
93
+ sampwidth = wf.getsampwidth()
94
+ raw = wf.readframes(wf.getnframes())
95
+
96
+ if sampwidth == 2:
97
+ arr = np.frombuffer(raw, dtype="<i2").astype(np.float32) / 32768.0
98
+ elif sampwidth == 4:
99
+ arr = np.frombuffer(raw, dtype="<i4").astype(np.float32) / 2147483648.0
100
+ elif sampwidth == 1:
101
+ arr = (np.frombuffer(raw, dtype=np.uint8).astype(np.float32) - 128.0) / 128.0
102
+ else:
103
+ raise ValueError(f"unsupported WAV sample width: {sampwidth} bytes")
104
+
105
+ if n_channels > 1:
106
+ arr = arr.reshape(-1, n_channels).mean(axis=1)
107
+ return np.ascontiguousarray(arr, dtype=np.float32), sr
@@ -0,0 +1,8 @@
1
+ """Optional backend subclasses for models that need glue beyond a plain signature."""
2
+ from .fsmn import FsmnVAD
3
+ from .marblenet import MarbleVAD
4
+ from .pyannote import PyannoteVAD
5
+ from .speechbrain import SbVAD
6
+ from .ten import TenVAD
7
+
8
+ __all__ = ["TenVAD", "FsmnVAD", "MarbleVAD", "SbVAD", "PyannoteVAD"]