inflectsynth 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,92 @@
1
+ """Inflect v2 prepared-text synthesis backed by ONNXVoice and InflectG2P."""
2
+
3
+ from importlib.metadata import PackageNotFoundError
4
+ from importlib.metadata import version as _distribution_version
5
+
6
+ from .api_contract import REQUEST_API_VERSION, request_api_contract
7
+ from .catalog import list_models
8
+ from .config import SynthesisConfig
9
+ from .discovery import DescribedVoice, DiscoveredModel, discover_models
10
+ from .errors import (
11
+ ArtifactIntegrityError,
12
+ CatalogDiscoveryError,
13
+ CatalogError,
14
+ CatalogUnavailableError,
15
+ EmptyTextError,
16
+ InflectSynthError,
17
+ InvalidSeedError,
18
+ InvalidSpeedError,
19
+ InvalidSynthesisConfigError,
20
+ InvalidVariationError,
21
+ InvalidVoiceError,
22
+ ModelInferenceError,
23
+ ModelNotFoundError,
24
+ OfflineModelError,
25
+ OnnxVoiceContractError,
26
+ ProviderUnavailableError,
27
+ UnsupportedModelError,
28
+ )
29
+ from .identity import runtime_identity
30
+ from .types import ModelInfo, SynthesisResult, VoiceInfo
31
+ from .voice import InflectVoice
32
+ from .voice_level import (
33
+ CalibrationDataError,
34
+ VoiceCalibrationCatalog,
35
+ VoiceCalibrationKey,
36
+ VoiceLevelApplication,
37
+ VoiceLevelCalibration,
38
+ VoiceLevelConfig,
39
+ VoiceLevelMode,
40
+ apply_voice_level_calibration,
41
+ default_voice_calibration,
42
+ load_voice_calibration,
43
+ )
44
+
45
+ try:
46
+ __version__ = _distribution_version("inflectsynth")
47
+ except PackageNotFoundError:
48
+ __version__ = "0+unknown"
49
+
50
+ __all__ = [
51
+ "__version__",
52
+ "REQUEST_API_VERSION",
53
+ "request_api_contract",
54
+ "runtime_identity",
55
+ "discover_models",
56
+ "DescribedVoice",
57
+ "DiscoveredModel",
58
+ "InflectVoice",
59
+ "SynthesisConfig",
60
+ "SynthesisResult",
61
+ "VoiceInfo",
62
+ "VoiceLevelConfig",
63
+ "VoiceLevelMode",
64
+ "VoiceCalibrationKey",
65
+ "VoiceLevelCalibration",
66
+ "VoiceCalibrationCatalog",
67
+ "VoiceLevelApplication",
68
+ "CalibrationDataError",
69
+ "apply_voice_level_calibration",
70
+ "default_voice_calibration",
71
+ "load_voice_calibration",
72
+ "InflectSynthError",
73
+ "EmptyTextError",
74
+ "InvalidSpeedError",
75
+ "InvalidVariationError",
76
+ "InvalidSeedError",
77
+ "InvalidVoiceError",
78
+ "InvalidSynthesisConfigError",
79
+ "UnsupportedModelError",
80
+ "OnnxVoiceContractError",
81
+ "ModelInferenceError",
82
+ "CatalogDiscoveryError",
83
+ "CatalogUnavailableError",
84
+ # Transitional prototype aliases, not part of the v0.1.0 request contract.
85
+ "list_models",
86
+ "ModelInfo",
87
+ "CatalogError",
88
+ "ModelNotFoundError",
89
+ "ArtifactIntegrityError",
90
+ "OfflineModelError",
91
+ "ProviderUnavailableError",
92
+ ]
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from .catalog import list_models
6
+ from .voice import InflectVoice
7
+
8
+
9
+ def parse_args() -> argparse.Namespace:
10
+ parser = argparse.ArgumentParser(description="Synthesize speech with Inflect v2 ONNX models")
11
+ parser.add_argument("text", nargs="?")
12
+ parser.add_argument("--model", default="nano-v2")
13
+ parser.add_argument("--voice", default="default")
14
+ parser.add_argument("--speed", type=float, default=1.0)
15
+ parser.add_argument("--variation", type=float, default=0.667)
16
+ parser.add_argument("--seed", type=int, default=0)
17
+ parser.add_argument("--provider", default="cpu")
18
+ parser.add_argument("--cache-dir")
19
+ parser.add_argument("--catalog-url")
20
+ parser.add_argument("--offline", action="store_true")
21
+ parser.add_argument("--force-download", action="store_true")
22
+ parser.add_argument("--list-models", action="store_true")
23
+ parser.add_argument("-o", "--output", default="inflect.wav")
24
+ return parser.parse_args()
25
+
26
+
27
+ def main() -> int:
28
+ args = parse_args()
29
+ if args.list_models:
30
+ for model in list_models(catalog_url=args.catalog_url):
31
+ print(f"{model.id}\t{model.name}\tvoices={','.join(v.id for v in model.voices)}")
32
+ return 0
33
+ if not args.text:
34
+ raise SystemExit("text is required unless --list-models is used")
35
+ with InflectVoice.from_pretrained(
36
+ args.model,
37
+ cache_dir=args.cache_dir,
38
+ catalog_url=args.catalog_url,
39
+ offline=args.offline,
40
+ force_download=args.force_download,
41
+ providers=args.provider,
42
+ ) as engine:
43
+ result = engine.synthesize(
44
+ args.text,
45
+ voice=args.voice,
46
+ speed=args.speed,
47
+ variation=args.variation,
48
+ seed=args.seed,
49
+ )
50
+ result.save_wav(args.output)
51
+ print(args.output)
52
+ return 0
53
+
54
+
55
+ if __name__ == "__main__":
56
+ raise SystemExit(main())
@@ -0,0 +1,298 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib
4
+ import os
5
+ from collections.abc import Mapping, Sequence
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from types import ModuleType
9
+ from typing import Any
10
+
11
+ from .errors import (
12
+ CatalogDiscoveryError,
13
+ CatalogUnavailableError,
14
+ InflectSynthError,
15
+ OnnxVoiceContractError,
16
+ UnsupportedModelError,
17
+ )
18
+
19
+ DEFAULT_CATALOG_URL = (
20
+ "https://raw.githubusercontent.com/buchwandler/inflect-onnx-bundles/main/catalog/models.json"
21
+ )
22
+
23
+
24
+ @dataclass(frozen=True, slots=True)
25
+ class ResolvedInflectModel:
26
+ ref: str | None
27
+ model_id: str
28
+ duration_path: Path
29
+ decode_path: Path
30
+ sample_rate: int
31
+ metadata: dict[str, Any]
32
+ installation: Any
33
+
34
+
35
+ def normalize_ref(value: str) -> str:
36
+ if not isinstance(value, str) or not value.strip():
37
+ raise OnnxVoiceContractError("Inflect model reference must not be empty")
38
+ return value if ":" in value else f"inflect:{value}"
39
+
40
+
41
+ def _module() -> ModuleType:
42
+ """Import ONNXVoice only when an operation needs its managed runtime."""
43
+ try:
44
+ module = importlib.import_module("onnxvoice")
45
+ except Exception as exc:
46
+ raise OnnxVoiceContractError(
47
+ "ONNXVoice with the Inflect adapter is required; install a compatible onnxvoice release"
48
+ ) from exc
49
+
50
+ manager_type = getattr(module, "OnnxVoice", None)
51
+ systems = getattr(module, "registered_systems", None)
52
+ try:
53
+ available_systems = systems() if callable(systems) else ()
54
+ except Exception as exc:
55
+ raise OnnxVoiceContractError("Could not inspect the ONNXVoice adapter registry") from exc
56
+ if manager_type is None or "inflect" not in available_systems:
57
+ raise OnnxVoiceContractError(
58
+ "Installed ONNXVoice does not expose the required Inflect adapter contract"
59
+ )
60
+ return module
61
+
62
+
63
+ def _manager(
64
+ *,
65
+ cache_dir: str | Path | None,
66
+ offline: bool,
67
+ catalog_url: str | None,
68
+ ) -> Any:
69
+ module = _module()
70
+ source = catalog_url or os.environ.get("INFLECTSYNTH_CATALOG_URL") or DEFAULT_CATALOG_URL
71
+ try:
72
+ return module.OnnxVoice(
73
+ cache_dir=cache_dir,
74
+ catalog_sources={"inflect": source},
75
+ offline=offline,
76
+ )
77
+ except TypeError as exc:
78
+ raise OnnxVoiceContractError(
79
+ "Installed ONNXVoice does not support the Inflect catalog_sources manager contract"
80
+ ) from exc
81
+
82
+
83
+ def _translate_onnxvoice_error(exc: Exception, operation: str) -> Exception:
84
+ """Translate ONNXVoice's public error families to stable InflectSynth errors."""
85
+ try:
86
+ errors = importlib.import_module("onnxvoice.errors")
87
+ except Exception:
88
+ return OnnxVoiceContractError(f"ONNXVoice {operation} operation failed")
89
+
90
+ def is_error(name: str) -> bool:
91
+ error_type = getattr(errors, name, None)
92
+ return isinstance(error_type, type) and isinstance(exc, error_type)
93
+
94
+ message = f"ONNXVoice {operation} operation failed: {exc}"
95
+ if is_error("OfflineError"):
96
+ return CatalogUnavailableError(message)
97
+ if is_error("CatalogError"):
98
+ return CatalogDiscoveryError(message)
99
+ if is_error("AssetNotFoundError") or is_error("IntegrityError"):
100
+ return UnsupportedModelError(message)
101
+ if is_error("AssetDownloadError"):
102
+ return UnsupportedModelError(message)
103
+ if is_error("RuntimeContractError") or is_error("OptionalDependencyError"):
104
+ return OnnxVoiceContractError(message)
105
+ if is_error("UnsupportedSystemError"):
106
+ return UnsupportedModelError(message)
107
+ if operation == "catalog":
108
+ return CatalogUnavailableError(message)
109
+ if operation == "install":
110
+ return UnsupportedModelError(message)
111
+ return OnnxVoiceContractError(message)
112
+
113
+
114
+ def installation_to_model(installation: Any) -> ResolvedInflectModel:
115
+ """Validate the public ONNXVoice installation shape required by InflectSynth."""
116
+ if getattr(installation, "system", None) != "inflect":
117
+ raise OnnxVoiceContractError("ONNXVoice installation system must be 'inflect'")
118
+ require_artifact = getattr(installation, "require_artifact", None)
119
+ if not callable(require_artifact):
120
+ raise OnnxVoiceContractError("ONNXVoice installation must support require_artifact(role)")
121
+ try:
122
+ duration = require_artifact("duration")
123
+ decode = require_artifact("decode")
124
+ except (KeyError, TypeError, ValueError) as exc:
125
+ raise OnnxVoiceContractError(
126
+ "ONNXVoice Inflect installation must contain duration and decode artifacts"
127
+ ) from exc
128
+
129
+ try:
130
+ duration_path = Path(duration.path)
131
+ decode_path = Path(decode.path)
132
+ metadata_value = installation.metadata
133
+ metadata = dict(metadata_value) if isinstance(metadata_value, Mapping) else {}
134
+ model_id = installation.id
135
+ except (AttributeError, TypeError, ValueError) as exc:
136
+ raise OnnxVoiceContractError("ONNXVoice returned an invalid Inflect installation") from exc
137
+ if not isinstance(model_id, str) or not model_id:
138
+ raise OnnxVoiceContractError("ONNXVoice Inflect installation must have a model id")
139
+
140
+ sample_rate = getattr(installation, "sample_rate", None)
141
+ if sample_rate is None:
142
+ sample_rate = metadata.get("sample_rate")
143
+ if sample_rate is None:
144
+ sample_rate = 24_000
145
+ if isinstance(sample_rate, bool) or not isinstance(sample_rate, int) or sample_rate <= 0:
146
+ raise OnnxVoiceContractError("ONNXVoice Inflect sample rate must be a positive integer")
147
+
148
+ metadata.setdefault("id", model_id)
149
+ metadata.setdefault("sample_rate", sample_rate)
150
+ metadata.setdefault("default_voice", getattr(installation, "default_voice", None) or "default")
151
+ if "voices" not in metadata:
152
+ voice_details = metadata.get("voice_details")
153
+ if isinstance(voice_details, Mapping):
154
+ metadata["voices"] = {key: dict(value) for key, value in voice_details.items()}
155
+
156
+ ref_value = getattr(installation, "ref", None)
157
+ ref = ref_value if isinstance(ref_value, str) else normalize_ref(model_id)
158
+ return ResolvedInflectModel(
159
+ ref=ref,
160
+ model_id=model_id,
161
+ duration_path=duration_path,
162
+ decode_path=decode_path,
163
+ sample_rate=sample_rate,
164
+ metadata=metadata,
165
+ installation=installation,
166
+ )
167
+
168
+
169
+ def install_pretrained_model(
170
+ model: str,
171
+ *,
172
+ cache_dir: str | Path | None = None,
173
+ offline: bool = False,
174
+ refresh_catalog: bool = False,
175
+ force_download: bool = False,
176
+ catalog_url: str | None = None,
177
+ progress: Any | None = None,
178
+ ) -> ResolvedInflectModel:
179
+ manager = _manager(cache_dir=cache_dir, offline=offline, catalog_url=catalog_url)
180
+ ref = normalize_ref(model)
181
+ try:
182
+ installation = manager.install(
183
+ ref,
184
+ refresh=refresh_catalog,
185
+ force=force_download,
186
+ progress=progress,
187
+ )
188
+ except TypeError as exc:
189
+ raise OnnxVoiceContractError(
190
+ "Installed ONNXVoice does not support the Inflect install contract"
191
+ ) from exc
192
+ except InflectSynthError:
193
+ raise
194
+ except Exception as exc:
195
+ raise _translate_onnxvoice_error(exc, "install") from exc
196
+ return installation_to_model(installation)
197
+
198
+
199
+ def open_installed_model(
200
+ model: ResolvedInflectModel,
201
+ *,
202
+ cache_dir: str | Path | None = None,
203
+ offline: bool = False,
204
+ catalog_url: str | None = None,
205
+ providers: Sequence[Any] | str | None = None,
206
+ provider_options: Sequence[dict[str, Any]] | dict[str, dict[str, Any]] | None = None,
207
+ session_options: Any | None = None,
208
+ ) -> Any:
209
+ manager = _manager(cache_dir=cache_dir, offline=offline, catalog_url=catalog_url)
210
+ try:
211
+ return manager.open(
212
+ model.installation,
213
+ providers=providers,
214
+ provider_options=provider_options,
215
+ session_options=session_options,
216
+ )
217
+ except TypeError as exc:
218
+ raise OnnxVoiceContractError(
219
+ "Installed ONNXVoice does not support provider/session options for Inflect models"
220
+ ) from exc
221
+ except InflectSynthError:
222
+ raise
223
+ except Exception as exc:
224
+ raise _translate_onnxvoice_error(exc, "open") from exc
225
+
226
+
227
+ def open_local_model(
228
+ *,
229
+ duration_path: str | Path,
230
+ decode_path: str | Path,
231
+ sample_rate: int = 24_000,
232
+ metadata: Mapping[str, Any] | None = None,
233
+ providers: Sequence[Any] | str | None = None,
234
+ provider_options: Sequence[dict[str, Any]] | dict[str, dict[str, Any]] | None = None,
235
+ session_options: Any | None = None,
236
+ ) -> Any:
237
+ module = _module()
238
+ try:
239
+ return module.OnnxVoice.open_local(
240
+ system="inflect",
241
+ artifacts={"duration": duration_path, "decode": decode_path},
242
+ sample_rate=sample_rate,
243
+ metadata=dict(metadata or {}),
244
+ providers=providers,
245
+ provider_options=provider_options,
246
+ session_options=session_options,
247
+ )
248
+ except TypeError as exc:
249
+ raise OnnxVoiceContractError(
250
+ "Installed ONNXVoice does not support local Inflect split-artifact opening"
251
+ ) from exc
252
+ except InflectSynthError:
253
+ raise
254
+ except Exception as exc:
255
+ raise _translate_onnxvoice_error(exc, "open_local") from exc
256
+
257
+
258
+ def catalog_items(
259
+ *,
260
+ language: str | None = None,
261
+ offline: bool = False,
262
+ refresh: bool = False,
263
+ cache_dir: str | Path | None = None,
264
+ catalog_url: str | None = None,
265
+ ) -> tuple[Any, ...]:
266
+ """Return catalog records only; never install or open model artifacts."""
267
+ manager = _manager(cache_dir=cache_dir, offline=offline, catalog_url=catalog_url)
268
+ try:
269
+ return tuple(manager.list("inflect", language=language, refresh=refresh))
270
+ except TypeError as exc:
271
+ raise OnnxVoiceContractError(
272
+ "Installed ONNXVoice does not support Inflect catalog discovery"
273
+ ) from exc
274
+ except InflectSynthError:
275
+ raise
276
+ except Exception as exc:
277
+ raise _translate_onnxvoice_error(exc, "catalog") from exc
278
+
279
+
280
+ def catalog_voices(
281
+ *,
282
+ language: str | None = None,
283
+ offline: bool = False,
284
+ refresh: bool = False,
285
+ cache_dir: str | Path | None = None,
286
+ catalog_url: str | None = None,
287
+ ) -> tuple[Any, ...]:
288
+ manager = _manager(cache_dir=cache_dir, offline=offline, catalog_url=catalog_url)
289
+ try:
290
+ return tuple(manager.list_voices("inflect", language=language, refresh=refresh))
291
+ except TypeError as exc:
292
+ raise OnnxVoiceContractError(
293
+ "Installed ONNXVoice does not support Inflect voice discovery"
294
+ ) from exc
295
+ except InflectSynthError:
296
+ raise
297
+ except Exception as exc:
298
+ raise _translate_onnxvoice_error(exc, "catalog") from exc
@@ -0,0 +1,29 @@
1
+ """Versioned, dependency-light declaration of the Readio request contract."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from types import MappingProxyType
7
+
8
+ REQUEST_API_VERSION = 1
9
+
10
+ _REQUEST_API_CONTRACT: Mapping[str, str | bool] = MappingProxyType(
11
+ {
12
+ "entrypoint": "InflectVoice.synthesize_prepared",
13
+ "supports_linguistic_tokens": False,
14
+ "supports_pronunciation_overrides": False,
15
+ "supports_whole_request_phonemes": False,
16
+ "supports_speakers": False,
17
+ "supports_word_timings": False,
18
+ "supports_voice_level": True,
19
+ "caller_owns_text_boundaries": True,
20
+ }
21
+ )
22
+
23
+
24
+ def request_api_contract() -> Mapping[str, str | bool]:
25
+ """Return an immutable declaration without catalog or model access."""
26
+ return _REQUEST_API_CONTRACT
27
+
28
+
29
+ __all__ = ["REQUEST_API_VERSION", "request_api_contract"]
@@ -0,0 +1,71 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from ._onnxvoice import catalog_items, catalog_voices
7
+ from .types import ModelInfo, VoiceInfo
8
+
9
+
10
+ def list_models(
11
+ *,
12
+ language: str | None = None,
13
+ offline: bool = False,
14
+ refresh: bool = False,
15
+ cache_dir: str | Path | None = None,
16
+ catalog_url: str | None = None,
17
+ ) -> tuple[ModelInfo, ...]:
18
+ """Compatibility discovery adapter backed exclusively by ONNXVoice."""
19
+ items = catalog_items(
20
+ language=language,
21
+ offline=offline,
22
+ refresh=refresh,
23
+ cache_dir=cache_dir,
24
+ catalog_url=catalog_url,
25
+ )
26
+ voices = catalog_voices(
27
+ language=language,
28
+ offline=offline,
29
+ refresh=refresh,
30
+ cache_dir=cache_dir,
31
+ catalog_url=catalog_url,
32
+ )
33
+ voices_by_model: dict[str, list[Any]] = {}
34
+ for record in voices:
35
+ voices_by_model.setdefault(record.asset_id, []).append(record)
36
+
37
+ models: list[ModelInfo] = []
38
+ for item in items:
39
+ metadata = item.metadata if isinstance(item.metadata, dict) else {}
40
+ upstream = metadata.get("upstream")
41
+ upstream = upstream if isinstance(upstream, dict) else {}
42
+ voice_details = metadata.get("voice_details")
43
+ voice_details = voice_details if isinstance(voice_details, dict) else {}
44
+ model_voices = tuple(
45
+ VoiceInfo(
46
+ id=record.voice_id,
47
+ name=str(voice_details.get(record.voice_id, {}).get("name", record.voice_id)),
48
+ language=record.metadata.locale,
49
+ gender=record.gender,
50
+ synthetic=bool(voice_details.get(record.voice_id, {}).get("synthetic", True)),
51
+ )
52
+ for record in voices_by_model.get(item.id, [])
53
+ )
54
+ models.append(
55
+ ModelInfo(
56
+ id=item.id,
57
+ name=str(metadata.get("name", item.id)),
58
+ aliases=tuple(item.aliases),
59
+ language=str(metadata.get("language", "en-US")),
60
+ sample_rate=int(item.sample_rate or 24_000),
61
+ default_voice=item.default_voice or "default",
62
+ voices=model_voices,
63
+ revision=str(
64
+ metadata.get("source_revision")
65
+ or upstream.get("source_revision")
66
+ or upstream.get("revision")
67
+ or ""
68
+ ),
69
+ )
70
+ )
71
+ return tuple(models)
inflectsynth/config.py ADDED
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from dataclasses import dataclass, field
5
+ from numbers import Real
6
+
7
+ from .errors import (
8
+ InvalidSeedError,
9
+ InvalidSpeedError,
10
+ InvalidSynthesisConfigError,
11
+ InvalidVariationError,
12
+ )
13
+ from .voice_level import VoiceLevelConfig
14
+
15
+
16
+ @dataclass(frozen=True, slots=True)
17
+ class SynthesisConfig:
18
+ speed: float = 1.0
19
+ variation: float = 0.667
20
+ seed: int = 0
21
+ voice_level: VoiceLevelConfig = field(default_factory=VoiceLevelConfig)
22
+
23
+ def validated(self) -> SynthesisConfig:
24
+ speed = _finite_control(self.speed, "speed", InvalidSpeedError)
25
+ if not 0.5 <= speed <= 2.0:
26
+ raise InvalidSpeedError("speed must be between 0.5 and 2.0")
27
+ variation = _finite_control(self.variation, "variation", InvalidVariationError)
28
+ if not 0.0 <= variation <= 1.0:
29
+ raise InvalidVariationError("variation must be between 0.0 and 1.0")
30
+ if isinstance(self.seed, bool) or not isinstance(self.seed, int) or self.seed < 0:
31
+ raise InvalidSeedError("seed must be a non-negative integer")
32
+ if not isinstance(self.voice_level, VoiceLevelConfig):
33
+ raise InvalidSynthesisConfigError("voice_level must be a VoiceLevelConfig")
34
+ return SynthesisConfig(
35
+ speed=speed,
36
+ variation=variation,
37
+ seed=self.seed,
38
+ voice_level=self.voice_level,
39
+ )
40
+
41
+
42
+ def _finite_control(
43
+ value: object,
44
+ name: str,
45
+ error_type: type[InvalidSynthesisConfigError],
46
+ ) -> float:
47
+ if isinstance(value, bool) or not isinstance(value, Real):
48
+ raise error_type(f"{name} must be a finite real number")
49
+ try:
50
+ number = float(value)
51
+ except (OverflowError, ValueError):
52
+ raise error_type(f"{name} must be a finite real number") from None
53
+ if not math.isfinite(number):
54
+ raise error_type(f"{name} must be finite")
55
+ return number
@@ -0,0 +1,32 @@
1
+ {
2
+ "corpus": "inflectsynth-prepared-speech-v1",
3
+ "generated_with": {
4
+ "audiosig": "0.1.6",
5
+ "inflectg2p": "0.1.0",
6
+ "inflectsynth": "0.1.dev2+gaed518a21",
7
+ "onnxvoice": "0.2.5"
8
+ },
9
+ "method": "bs1770",
10
+ "reference_lufs": -24.0,
11
+ "schema": 1,
12
+ "voices": {
13
+ "inflect:micro-v2:default": {
14
+ "corpus_version": "inflectsynth-prepared-speech-v1",
15
+ "gain_db": -0.3353773192815517,
16
+ "mad_lu": 0.28835105130528405,
17
+ "measured_lufs": -23.66462268071845,
18
+ "method": "bs1770",
19
+ "reference_lufs": -24.0,
20
+ "samples": 9
21
+ },
22
+ "inflect:nano-v2:default": {
23
+ "corpus_version": "inflectsynth-prepared-speech-v1",
24
+ "gain_db": -0.042377569773361046,
25
+ "mad_lu": 0.2913390390127759,
26
+ "measured_lufs": -23.95762243022664,
27
+ "method": "bs1770",
28
+ "reference_lufs": -24.0,
29
+ "samples": 9
30
+ }
31
+ }
32
+ }