@qvac/tts-ggml 0.11.1 → 0.13.0

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.
package/README.md CHANGED
@@ -29,7 +29,8 @@ Xclipse/Mali → Vulkan). Parler supports Apple/Metal, linux CUDA, and the
29
29
  validated Android paths, including Vulkan on ARM Mali (see
30
30
  [Backends & GPU acceleration](#backends--gpu-acceleration)). Audio8 supports
31
31
  CUDA/Vulkan offload on Linux and Vulkan on Windows. MOSS GPU offload is
32
- validated on Apple/Metal.
32
+ validated on Apple/Metal; desktop CUDA/Vulkan validation requires the native
33
+ and registry prerequisites described under [MOSS](#moss).
33
34
 
34
35
  [qvac-tts-cpp]: https://github.com/tetherto/qvac-fabric-speech.cpp/tree/master/engines/tts
35
36
 
@@ -54,8 +55,9 @@ validated on Apple/Metal.
54
55
  iOS, picked up when staged next to the model (see
55
56
  [Core ML sidecars on Apple](#core-ml-sidecars-on-apple)).
56
57
  - **Dynamic backend loading on Android** — per-arch CPU + Vulkan +
57
- OpenCL `.so` files ship under `prebuilds/<bare-target>/qvac__tts-ggml/`
58
- and are picked up at runtime via the new `backendsDir` option (see
58
+ OpenCL `.so` files ship under
59
+ `prebuilds/<bare-target>/qvac__tts-ggml-android-arm64/` and the addon picks
60
+ them up at runtime from next to its native module (see
59
61
  [Backends & GPU acceleration](#backends--gpu-acceleration)).
60
62
  - **Cancellation** via `model.cancel()` — stops T3 decode on the next
61
63
  token; in-flight S3Gen chunk runs to completion.
@@ -150,11 +152,10 @@ package selected at install time through `os`/`cpu` filtered
150
152
 
151
153
  Do not depend on desktop platform packages directly. Supported installers are
152
154
  npm 7+, pnpm, bun, and Yarn Berry. Yarn v1 and `--omit=optional` installs skip
153
- the platform package and fail at require time with an error naming the missing
154
- package; a locally built `prebuilds/` directory in the package root always
155
- takes precedence. Use `require('@qvac/tts-ggml').resolveBackendsDir()` to
156
- locate the directory holding the host's prebuilt binaries and dynamically
157
- loaded ggml backends. Unsupported targets must
155
+ the platform package and fail at require time, and at `bare-pack` time, naming
156
+ the missing package. Each platform package is an ordinary Bare addon whose
157
+ `prebuilds/<host>/` holds the native module and, next to it, the dynamically
158
+ loaded ggml backends the module finds on its own. Unsupported targets must
158
159
  [build from source](#build-from-source); installation does not automatically
159
160
  compile a local addon.
160
161
 
@@ -805,13 +806,13 @@ registration and the addon falls back to Vulkan or CPU.
805
806
 
806
807
  Android prebuilds enable `GGML_BACKEND_DL=ON` and ship per-arch
807
808
  backend `.so` files under
808
- `prebuilds/<bare-target>/qvac__tts-ggml/`.
809
+ `prebuilds/android-arm64/qvac__tts-ggml-android-arm64/` of
810
+ `@qvac/tts-ggml-android-arm64`; `bare-link` puts them next to the module in
811
+ the app, where the addon looks when `backendsDir` is unset.
809
812
 
810
813
  The engine `dlopen()`s the highest-tier CPU variant the device's
811
814
  HWCAPs support and one of the GPU `.so` files based on the policy
812
- table above. Hosts must pass `backendsDir: path.join(__dirname,
813
- 'prebuilds')` (or rely on the default fallback the package ships)
814
- so the runtime knows where to look. `openclCacheDir` is also
815
+ table above. `openclCacheDir` is
815
816
  Android-specific; setting it to a writable path lets the OpenCL
816
817
  backend persist its compiled program cache across launches.
817
818
  `vulkanCacheDir` is the Vulkan analogue (Supertonic + `useGPU: true`):
@@ -1060,6 +1061,82 @@ falls back to CPU and sets `response.stats.gpuUnsupported`. `backendsDir`
1060
1061
  reaches MOSS like every other engine, so builds that load ggml backends at
1061
1062
  runtime find them.
1062
1063
 
1064
+ The same controls apply to MOSS-TTSD and MOSS-Speech. `nGpuLayers` is a
1065
+ boolean GPU request for these engines (zero = CPU, non-zero = GPU), not a
1066
+ partial layer count. The addon forwards these controls to the native engine;
1067
+ it does not choose a different backend or change the CPU default.
1068
+ `response.stats.backendId` identifies the language-model backend (2 = CUDA,
1069
+ 3 = Vulkan); it is not a measurement of every codec operation.
1070
+
1071
+ The combined desktop CUDA/Vulkan speech changes in
1072
+ [Vulkan #308](https://github.com/tetherto/qvac-fabric-speech.cpp/pull/308),
1073
+ including [CUDA #321](https://github.com/tetherto/qvac-fabric-speech.cpp/pull/321),
1074
+ merged to native master at `84b02694001cfea863167776dbc185474a816656`.
1075
+ This checkout consumes the merged [registry #423](https://github.com/tetherto/qvac-registry-vcpkg/pull/423)
1076
+ at `e31be272ecdf9f20970302ebf8a2943d47803001`: `speech-cpp` 2026-10-12#1
1077
+ pins that merged revision, and `ggml-speech` 2026-10-07#1 pins
1078
+ `06f1b66806626a635904f31db6914ad2d0e71197`. The earlier native `f4d4c257`
1079
+ passed ten smaller-model CUDA/Vulkan cases; those results do not establish GPU
1080
+ validation of the final native revision or the packaged addon. Rebuild the addon
1081
+ before running its GPU tests. Native desktop results also do not establish
1082
+ Android support or speech-quality signoff.
1083
+
1084
+ The registry `baseline` is the main commit containing #423. The shared exact
1085
+ `speech-cpp` overrides and backend implementation are already on qvac main.
1086
+ This baseline update completes the TTS registry configuration; packaged-addon
1087
+ CUDA/Vulkan inference still requires validation on provisioned GPU hosts before
1088
+ claiming a validated release.
1089
+
1090
+ From `packages/tts-ggml`, resolve the checked-in manifest without building or
1091
+ downloading models (with `VCPKG_ROOT` set):
1092
+
1093
+ ```sh
1094
+ vcpkg install --dry-run --triplet x64-linux --x-feature=cuda --x-feature=vulkan
1095
+ ```
1096
+
1097
+ On a macOS host without a Linux cross-compiler, prefix that dry-run command
1098
+ with `VCPKG_FEATURE_FLAGS=-compilertracking` to check registry resolution only.
1099
+ For a bounded native build on a suitably provisioned Linux GPU host:
1100
+
1101
+ ```sh
1102
+ CMAKE_BUILD_PARALLEL_LEVEL=2 VCPKG_MAX_CONCURRENCY=2 npm run build:cuda
1103
+ ```
1104
+
1105
+ The normal PR workflow requires approval of the `fork-ci` environment for
1106
+ external forks. Obtain that approval through the existing gate; a manual
1107
+ workflow dispatch is not a substitute for fork approval.
1108
+
1109
+ On a desktop with those prerequisites, stage the TTS and TTSD backbones,
1110
+ codec decoder/encoder and the bundled `test/reference-audio/jfk.wav`, plus
1111
+ the Speech model/codec. Set
1112
+ `QVAC_TEST_MOSS_MODEL_DIR` and `QVAC_TEST_MOSS_SPEECH_MODEL_DIR` to their
1113
+ respective directories. Run each available backend in a fresh process:
1114
+
1115
+ ```sh
1116
+ QVAC_TEST_MOSS_FULL_GPU=true TTS_CPP_GPU_BACKEND=cuda npx --no-install brittle-bare test/integration/moss.test.js test/integration/moss-speech.test.js
1117
+ QVAC_TEST_MOSS_FULL_GPU=true TTS_CPP_GPU_BACKEND=vulkan npx --no-install brittle-bare test/integration/moss.test.js test/integration/moss-speech.test.js
1118
+ ```
1119
+
1120
+ The tests check the exact pinned backend, `backendDevice` and
1121
+ `gpuUnsupported` for TTS batch/streaming/cloning, TTSD dialogue, and Speech
1122
+ text/audio replies. CPU control cases still require CPU even with a GPU pin.
1123
+ `QVAC_TEST_MOSS_FULL_GPU=true` fails before model loading unless both model
1124
+ directories, the TTS/TTSD/Speech backbones, all three codec GGUFs, and the
1125
+ reference WAV exist. It also requires an explicit backend pin (case-insensitive),
1126
+ rejects `NO_GPU=true` and mobile CPU-only cases, and checks that every required
1127
+ case completes. Run both files together without test filters: a successful full
1128
+ run has 12 passing tests, including the two completion checks, and no skips.
1129
+ Preflight only checks asset presence; actual model loading and inference must
1130
+ also pass. These commands cover TTS, TTSD and Speech, not MOSS-SoundEffect (SFX).
1131
+ No addon CUDA/Vulkan hardware run has been completed for this test change yet.
1132
+
1133
+ Without strict mode, developer behavior is unchanged: an unpinned run accepts
1134
+ the normal GPU cascade, missing model directories skip tests, and missing
1135
+ encoder/TTSD assets omit cloning/dialogue cases. Such runs are not full GPU
1136
+ validation. `npm run test:node` covers backend selection and strict validation
1137
+ failures without loading models. Do not load these multi-GB models on
1138
+ memory-constrained hosts.
1139
+
1063
1140
  ## MOSS-SoundEffect
1064
1141
 
1065
1142
  MOSS-SoundEffect-v2 generates a sound effect from a text description: a Qwen3
@@ -1228,7 +1305,7 @@ instance. Runtime stats add `promptTokens`, `generatedTokens`, `replyTokens`,
1228
1305
  | `promptText` | string | — | CosyVoice3-only: verbatim transcript of `referenceAudio` — set for zero-shot cloning, omit for cross-lingual; without a reference it overrides the baked voice's transcript |
1229
1306
  | `mecabDictDir` | string | — | Chatterbox MTL Japanese (`ja`): compiled MeCab/IPAdic dictionary directory |
1230
1307
  | `cangjieTsvPath` | string | — | Chatterbox MTL Chinese (`zh`): `Cangjie5_TC` TSV path |
1231
- | `backendsDir` | string | `resolveBackendsDir()` | Root dir the addon scans for dynamically-loaded ggml backend `.so` files. Defaults to the package's own `prebuilds/` when present, otherwise the installed platform package. Required on Android when backends ship elsewhere (e.g. inside the APK); ignored on platforms that statically link the backend |
1308
+ | `backendsDir` | string | the module's own | Directory the addon scans, as given, for dynamically-loaded ggml backend `.so` / `.dll` files. Unset scans the directory the native module was loaded from (`prebuilds/<host>/qvac__tts-ggml-<suffix>/` in a platform package, the app's native library directory after `bare-link`); ignored on platforms that statically link the backend |
1232
1309
  | `openclCacheDir` | string | unset | Android-only: directory where the OpenCL backend persists its compiled program-binary cache. Setting it across runs avoids re-JITing the kernels on every fresh process |
1233
1310
  | `vulkanCacheDir` | string | unset | Supertonic + `useGPU: true` only: writable directory where the Vulkan backend persists its compiled pipeline cache (`GGML_VK_PIPELINE_CACHE_DIR`). Moves the one-time first-dispatch pipeline-compile cost (seconds on Mali) off the first `run()` — paid once per install instead of once per process — and enables a load-time pre-warm. Fully opt-in: unset -> no cross-process cache, no pre-warm, behaviour unchanged |
1234
1311
  | `config.language` | string | `"en"` | Chatterbox MTL accepts `es/fr/de/pt/it/zh/ja/ko/...`; turbo & Supertonic are English; MOSS takes it as a prompt hint (`en`, `zh`, ...) |
@@ -1348,12 +1425,14 @@ const {
1348
1425
 
1349
1426
  `assessFit` projects a load against the memory free right now. It reads GGUF metadata and never weight data, so the registry's weightless copy of each file answers the same as the file itself and the projection can run before anything is downloaded. It is a module export, not an instance method: nothing is loaded to call it.
1350
1427
 
1428
+ `assessFit` returns a Promise. Fits run one at a time within this addon.
1429
+
1351
1430
  A request is a `createInstance` config plus the workload, so it carries the same keys the load takes and the engine's own config builder reads it.
1352
1431
 
1353
1432
  ```js
1354
1433
  const TTSGgml = require('@qvac/tts-ggml')
1355
1434
 
1356
- const fit = TTSGgml.assessFit({
1435
+ const fit = await TTSGgml.assessFit({
1357
1436
  engineType: 'supertonic',
1358
1437
  supertonicModelPath: '/models/supertonic.gguf',
1359
1438
  useGPU: true,
@@ -1393,7 +1472,7 @@ Everything else comes from the load config: `nGpuLayers` and `useGPU` carry the
1393
1472
 
1394
1473
  `deviceSharesHostMemory` reports that the device pool is system RAM, so host bytes compete with device bytes.
1395
1474
 
1396
- A model the engine cannot read is `status: "error"`, as is a voice with no fitter, which reports `reason: "unsupported-engine"`. MOSS-TTS, MOSS-TTSD and MOSS-SoundEffect are supported. MOSS-Speech has no SDK fit projection. A broken request, or a host with no native binding, throws.
1475
+ A model the engine cannot read resolves to `status: "error"`, as does a voice with no fitter, which reports `reason: "unsupported-engine"`. MOSS-TTS, MOSS-TTSD and MOSS-SoundEffect are supported. MOSS-Speech has no SDK fit projection. A broken request, or a host with no native binding, rejects.
1397
1476
 
1398
1477
  MOSS-TTS and MOSS-TTSD share the `moss` fitter. `promptRows` is the complete
1399
1478
  native prompt length, including special tokens, encoded speaker references and
@@ -1404,7 +1483,7 @@ The fitter does not open reference recordings. Use the TTSD backbone to assess
1404
1483
  dialogue, supplying its complete prompt and total reference workload.
1405
1484
 
1406
1485
  ```js
1407
- const fit = TTSGgml.assessFit({
1486
+ const fit = await TTSGgml.assessFit({
1408
1487
  engineType: 'moss',
1409
1488
  mossBackbonePath: './moss-tts-delay-f16.gguf',
1410
1489
  mossCodecDecoderPath: './moss-codec-decoder-f16.gguf',
@@ -1426,7 +1505,7 @@ The supertonic fitter covers the fused graph path: a validated GPU, or a CPU wit
1426
1505
  ### MOSS-SoundEffect fit
1427
1506
 
1428
1507
  ```js
1429
- const fit = TTSGgml.assessFit({
1508
+ const fit = await TTSGgml.assessFit({
1430
1509
  engineType: 'moss-sfx',
1431
1510
  mossSoundEffectPath: './moss-sfx-v2-q8_0.gguf',
1432
1511
  prompt: 'Rain falling on a tin roof.',
@@ -1571,11 +1650,18 @@ npm install
1571
1650
  npx bare-make generate # configures + fetches the tts-cpp port
1572
1651
  npx bare-make build
1573
1652
  npx bare-make install # copies the .bare into prebuilds/<triple>/
1653
+ npm run link:platform # stages node_modules/@qvac/tts-ggml-<host>
1574
1654
  ```
1575
1655
 
1656
+ `require('#host-addon')` only ever loads a platform package, so a source
1657
+ build becomes loadable once `npm run link:platform` (run by
1658
+ `npm run build:native`) wraps `prebuilds/<host>/` as that host's
1659
+ `@qvac/tts-ggml-<host>` package in `node_modules/`.
1660
+
1576
1661
  The vcpkg port is hosted in
1577
1662
  [`tetherto/qvac-registry-vcpkg`][registry] and pulls
1578
- [`qvac-tts.cpp`][qvac-tts-cpp] at a pinned REF. See
1663
+ [`qvac-fabric-speech.cpp`](https://github.com/tetherto/qvac-fabric-speech.cpp)
1664
+ (`engines/tts`) at a pinned REF. See
1579
1665
  [`vcpkg-configuration.json`](./vcpkg-configuration.json) for the
1580
1666
  baseline commit.
1581
1667
 
@@ -1,31 +1,15 @@
1
- const { hostPlatformPackage, PREBUILT_HOSTS } = require('./lib/backends.js')
1
+ 'use strict'
2
2
 
3
- const META_PACKAGE = '@qvac/tts-ggml'
4
- const UNKNOWN_HOST = 'unknown'
3
+ // "#host-addon" target for hosts with no platform package. Hosts that have one
4
+ // map straight to it with no fallback, so a missing install fails bare-pack (and
5
+ // fails at run time naming the package) instead of producing a bundle that only
6
+ // throws once launched.
7
+ const host = require.addon ? require.addon.host : 'unknown'
5
8
 
6
- throw new Error(buildMessage(currentHost()))
7
-
8
- function currentHost() {
9
- return require.addon ? require.addon.host : null
10
- }
11
-
12
- function buildMessage(host) {
13
- if (!host || !PREBUILT_HOSTS.includes(host)) {
14
- return (
15
- META_PACKAGE +
16
- ' has no prebuilt binaries for host ' +
17
- (host || UNKNOWN_HOST) +
18
- '. Prebuilt hosts: ' +
19
- PREBUILT_HOSTS.join(', ') +
20
- '. Build from source with bare-make.'
21
- )
22
- }
23
- return (
24
- META_PACKAGE +
25
- ' found no native prebuild for ' +
9
+ throw new Error(
10
+ '@qvac/tts-ggml has no prebuilt binaries for host ' +
26
11
  host +
27
- ': the platform package ' +
28
- hostPlatformPackage(host) +
29
- ' is not installed. It ships as an os/cpu filtered optional dependency, which Yarn v1 and installs using --omit=optional drop. Reinstall with npm 7+, pnpm, bun, or Yarn Berry, or build from source with bare-make.'
30
- )
31
- }
12
+ '. Platform packages exist for linux-x64, linux-arm64, darwin-arm64, ' +
13
+ 'darwin-x64, win32-x64, android-arm64 and ios (ios-arm64, ' +
14
+ 'ios-arm64-simulator, ios-x64-simulator). Build from source with bare-make.'
15
+ )
package/binding.js CHANGED
@@ -1,52 +1 @@
1
- module.exports = loadAddon()
2
-
3
- // `require.addon()` reads the prebuild shipped inside this package. Since the
4
- // per-platform split (0.9.0) there is none, so the real binding almost always
5
- // comes from the `#host-addon` platform package. Runtimes have been seen to
6
- // answer `require.addon()` with this package's own JavaScript entry instead of
7
- // failing, which used to be returned verbatim: callers then got a module with
8
- // no `createInstance`, and the first symptom was an unrelated TypeError deep in
9
- // a model load. Anything that is not the native binding is treated as a miss.
10
- function loadAddon() {
11
- let cause = null
12
-
13
- try {
14
- const addon = require.addon()
15
- if (isNativeBinding(addon)) return addon
16
- cause = new Error(
17
- '@qvac/tts-ggml: require.addon() answered with a module that is not the native binding ' +
18
- '(no createInstance function), so the prebuild in this package was treated as absent.'
19
- )
20
- } catch (err) {
21
- cause = err
22
- }
23
-
24
- return loadPlatformPackageAddon(cause)
25
- }
26
-
27
- function loadPlatformPackageAddon(cause) {
28
- let addon
29
-
30
- try {
31
- addon = require('#host-addon')
32
- } catch (err) {
33
- if (err.cause === undefined) err.cause = cause
34
- throw err
35
- }
36
-
37
- if (!isNativeBinding(addon)) {
38
- const err = new Error(
39
- '@qvac/tts-ggml resolved #host-addon to a module that is not the native binding: ' +
40
- 'it has no createInstance function. Check that the platform package for this host ' +
41
- 'is installed and is not shadowed by another module of the same name.'
42
- )
43
- err.cause = cause
44
- throw err
45
- }
46
-
47
- return addon
48
- }
49
-
50
- function isNativeBinding(addon) {
51
- return addon !== null && typeof addon === 'object' && typeof addon.createInstance === 'function'
52
- }
1
+ module.exports = require('#host-addon')
@@ -8,11 +8,18 @@ if (!model || !prompt || seconds === undefined) {
8
8
  throw new Error('Usage: bare examples/moss-sfx-fit.js <model.gguf> <prompt> <seconds>')
9
9
  }
10
10
 
11
- const fit = TTSGgml.assessFit({
12
- engineType: 'moss-sfx',
13
- mossSoundEffectPath: model,
14
- prompt,
15
- seconds: Number(seconds),
16
- useGPU: false
11
+ async function main() {
12
+ const fit = await TTSGgml.assessFit({
13
+ engineType: 'moss-sfx',
14
+ mossSoundEffectPath: model,
15
+ prompt,
16
+ seconds: Number(seconds),
17
+ useGPU: false
18
+ })
19
+ console.log(fit.report || `${fit.status}: ${fit.reason}`)
20
+ }
21
+
22
+ main().catch((err) => {
23
+ console.error(err)
24
+ process.exit(1)
17
25
  })
18
- console.log(fit.report || `${fit.status}: ${fit.reason}`)
package/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { type QvacResponse } from "@qvac/infer-base";
2
2
  import * as errorModule from "./lib/error";
3
- import { resolveBackendsDir as resolveBackendsDirImpl } from "./lib/backends";
4
3
  import { assessFit as assessFitImpl, type Audio8FitRequest, type MossFitRequest, type MossSoundEffectFitRequest, type ChatterboxFitRequest, type CosyvoiceFitRequest, type ParlerFitRequest, type SupertonicFitRequest, type TtsFitEngine, type TtsFitRequest, type TtsFitResult, type TtsFitStatus } from "./lib/fit";
5
4
  import { type SentenceDelimiterPreset } from "./lib/textStreamAccumulator";
6
5
  declare const ENGINE_CHATTERBOX = "chatterbox";
@@ -607,7 +606,11 @@ interface TTSGgmlOptions extends ParlerDescriptionFields, Audio8VoiceFields, TTS
607
606
  * streaming (batch synthesis only).
608
607
  */
609
608
  denoiser?: LavaSRDenoiserOptions;
610
- /** Directory the addon scans for dynamically loaded ggml backends. */
609
+ /**
610
+ * Directory the addon scans for dynamically loaded ggml backends, as given.
611
+ * Unset scans the addon's own: the one its platform package or the app
612
+ * installed next to the native module.
613
+ */
611
614
  backendsDir?: string;
612
615
  /** Directory where ggml-opencl persists its compiled program binary. */
613
616
  openclCacheDir?: string;
@@ -1211,7 +1214,6 @@ declare namespace TTSGgml {
1211
1214
  type MossFitRequest = NamespaceMossFit;
1212
1215
  type MossSoundEffectFitRequest = NamespaceMossSoundEffectFit;
1213
1216
  type CosyvoiceFitRequest = NamespaceCosyvoiceFit;
1214
- const resolveBackendsDir: typeof resolveBackendsDirImpl;
1215
1217
  const assessFit: typeof assessFitImpl;
1216
1218
  }
1217
1219
  export = TTSGgml;
package/index.js CHANGED
@@ -46,7 +46,6 @@ const infer_base_1 = require("@qvac/infer-base");
46
46
  const tts_1 = require("./tts");
47
47
  const errorModule = __importStar(require("./lib/error"));
48
48
  const pocketConfig_1 = require("./lib/pocketConfig");
49
- const backends_1 = require("./lib/backends");
50
49
  const fit_1 = require("./lib/fit");
51
50
  const textChunker_1 = require("./lib/textChunker");
52
51
  const textStreamAccumulator_1 = require("./lib/textStreamAccumulator");
@@ -1293,7 +1292,7 @@ class TTSGgml {
1293
1292
  this._assignSynthesisOptions(options);
1294
1293
  this._enhancerGgufPath = resolveEnhancerGgufPath(normalizedFiles, options.enhancer);
1295
1294
  this._denoiserGgufPath = resolveDenoiserGgufPath(normalizedFiles, options.denoiser);
1296
- this._backendsDir = firstNonEmpty(options.backendsDir, this._config.backendsDir, (0, backends_1.resolveBackendsDir)());
1295
+ this._backendsDir = firstNonEmpty(options.backendsDir, this._config.backendsDir);
1297
1296
  this._openclCacheDir = firstNonEmpty(options.openclCacheDir, this._config.openclCacheDir);
1298
1297
  this._vulkanCacheDir = firstNonEmpty(options.vulkanCacheDir, this._config.vulkanCacheDir);
1299
1298
  assertGpuIntentConsistent(this._config.useGPU, this._nGpuLayers);
@@ -3311,7 +3310,6 @@ class TTSGgml {
3311
3310
  (function (TTSGgml) {
3312
3311
  TTSGgml.QvacErrorAddonTTSGgml = errorModule.QvacErrorAddonTTSGgml;
3313
3312
  TTSGgml.ERR_CODES = errorModule.ERR_CODES;
3314
- TTSGgml.resolveBackendsDir = backends_1.resolveBackendsDir;
3315
3313
  TTSGgml.assessFit = fit_1.assessFit;
3316
3314
  })(TTSGgml || (TTSGgml = {}));
3317
3315
  module.exports.QvacErrorAddonTTSGgml =
package/lib/fit.d.ts CHANGED
@@ -139,9 +139,9 @@ export interface TtsFitResult {
139
139
  *
140
140
  * `engineType` picks the fitter, the same key a load uses, and is required
141
141
  * here: a fit request carries none of the file keys a load is inferred from.
142
- * A model the engine cannot read comes back as `status: "error"`, as does a
142
+ * A model the engine cannot read resolves to `status: "error"`, as does a
143
143
  * voice with no fitter; a broken request, or a host with no native binding,
144
- * throws.
144
+ * rejects. Fits run one at a time within this addon.
145
145
  */
146
- export declare function assessFit(request: TtsFitRequest): TtsFitResult;
146
+ export declare function assessFit(request: TtsFitRequest): Promise<TtsFitResult>;
147
147
  export {};
package/lib/fit.js CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assessFit = assessFit;
4
- const backends_1 = require("./backends");
5
4
  /**
6
5
  * Projects one voice against the memory free right now, reading GGUF metadata
7
6
  * and never weight data. The registry's weightless copy of each file answers
@@ -13,17 +12,12 @@ const backends_1 = require("./backends");
13
12
  *
14
13
  * `engineType` picks the fitter, the same key a load uses, and is required
15
14
  * here: a fit request carries none of the file keys a load is inferred from.
16
- * A model the engine cannot read comes back as `status: "error"`, as does a
15
+ * A model the engine cannot read resolves to `status: "error"`, as does a
17
16
  * voice with no fitter; a broken request, or a host with no native binding,
18
- * throws.
17
+ * rejects. Fits run one at a time within this addon.
19
18
  */
20
- function assessFit(request) {
21
- // eslint-disable-next-line @typescript-eslint/no-require-imports -- native binding is resolved lazily from package prebuilds.
19
+ async function assessFit(request) {
20
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- the native binding loads on first use.
22
21
  const binding = require('../binding.js');
23
- return binding.assessFit({
24
- ...request,
25
- backendsDir: typeof request.backendsDir === 'string' && request.backendsDir.length > 0
26
- ? request.backendsDir
27
- : (0, backends_1.resolveBackendsDir)()
28
- });
22
+ return await binding.assessFit(request);
29
23
  }
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@qvac/tts-ggml",
3
- "version": "0.11.1",
3
+ "version": "0.13.0",
4
4
  "description": "Text to Speech (TTS) addon for qvac (ggml backend, wrapping the chatterbox + supertonic + parler + cosyvoice3 + audio8 + moss + moss-sfx + moss-speech + Pocket engines from tts-cpp)",
5
- "addon": true,
6
5
  "qvac": {
7
6
  "ggml-speech": "2026-10-07#1"
8
7
  },
@@ -12,52 +11,32 @@
12
11
  "imports": {
13
12
  "#host-addon": {
14
13
  "linux": {
15
- "x64": [
16
- "@qvac/tts-ggml-linux-x64",
17
- "./addon-unavailable.js"
18
- ],
19
- "arm64": [
20
- "@qvac/tts-ggml-linux-arm64",
21
- "./addon-unavailable.js"
22
- ],
14
+ "x64": "@qvac/tts-ggml-linux-x64",
15
+ "arm64": "@qvac/tts-ggml-linux-arm64",
23
16
  "default": "./addon-unavailable.js"
24
17
  },
25
18
  "darwin": {
26
- "arm64": [
27
- "@qvac/tts-ggml-darwin-arm64",
28
- "./addon-unavailable.js"
29
- ],
30
- "x64": [
31
- "@qvac/tts-ggml-darwin-x64",
32
- "./addon-unavailable.js"
33
- ],
19
+ "arm64": "@qvac/tts-ggml-darwin-arm64",
20
+ "x64": "@qvac/tts-ggml-darwin-x64",
34
21
  "default": "./addon-unavailable.js"
35
22
  },
36
23
  "win32": {
37
- "x64": [
38
- "@qvac/tts-ggml-win32-x64",
39
- "./addon-unavailable.js"
40
- ],
24
+ "x64": "@qvac/tts-ggml-win32-x64",
41
25
  "default": "./addon-unavailable.js"
42
26
  },
43
27
  "android": {
44
- "arm64": [
45
- "@qvac/tts-ggml-android-arm64",
46
- "./addon-unavailable.js"
47
- ],
28
+ "arm64": "@qvac/tts-ggml-android-arm64",
48
29
  "default": "./addon-unavailable.js"
49
30
  },
50
- "ios": [
51
- "@qvac/tts-ggml-ios",
52
- "./addon-unavailable.js"
53
- ],
31
+ "ios": "@qvac/tts-ggml-ios",
54
32
  "default": "./addon-unavailable.js"
55
33
  }
56
34
  },
57
35
  "scripts": {
58
36
  "build": "npm run build:ts && npm run build:native",
59
- "build:native": "bare-make generate -D BUILD_FUZZING=OFF && bare-make build && bare-make install",
60
- "build:native:cuda": "bare-make generate -D ENABLE_CUDA=ON -D BUILD_FUZZING=OFF && bare-make build && bare-make install",
37
+ "build:native": "bare-make generate -D BUILD_FUZZING=OFF && bare-make build && bare-make install && npm run link:platform",
38
+ "build:native:cuda": "bare-make generate -D ENABLE_CUDA=ON -D BUILD_FUZZING=OFF && bare-make build && bare-make install && npm run link:platform",
39
+ "link:platform": "node ../../scripts/ci/slice-platform-packages.mjs --link-local --workdir .",
61
40
  "build:cuda": "npm run build:ts && npm run build:native:cuda",
62
41
  "build:ts": "tsc -p tsconfig.build.json",
63
42
  "build:pack": "npm run build:ts && mkdir -p dist && npm pack --pack-destination dist",
@@ -86,10 +65,10 @@
86
65
  "example:moss-sfx": "bare examples/moss-sound-effect.js \"Heavy rain falling on a tin roof with distant thunder.\" 5",
87
66
  "example:moss-speech": "bare examples/moss-speech.js test/reference-audio/jfk.wav",
88
67
  "lint": "npm run lint:js && npm run lint:ts && npm run test:types",
89
- "lint:js": "prettier --check \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/binding-loader.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\" && lunte \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/binding-loader.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\"",
68
+ "lint:js": "prettier --check \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\" && lunte \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\"",
90
69
  "lint:ts": "eslint \"src/**/*.ts\" --max-warnings=0",
91
70
  "lint:ts:fix": "eslint \"src/**/*.ts\" --fix",
92
- "format": "prettier --write \"test/**/*.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/binding-loader.test.js\" \"binding.js\" \"addon-unavailable.js\"",
71
+ "format": "prettier --write \"test/**/*.js\" \"scripts/__tests__/package-contract.test.js\" \"binding.js\" \"addon-unavailable.js\"",
93
72
  "test:unit": "npm run build:ts && brittle-bare test/unit/**/*.test.js && npm run test:node",
94
73
  "test:node": "node --test scripts/__tests__/*.test.js",
95
74
  "test": "npm run test:types && npm run test:unit && npm run test:integration",
@@ -147,6 +126,11 @@
147
126
  "test/pocket-worklet",
148
127
  "test/reference-audio",
149
128
  "test/utils/runTTS.js",
129
+ "test/utils/mossBackend.js",
130
+ "test/utils/mossGpuValidation.js",
131
+ "test/utils/gpuOnly.js",
132
+ "test/utils/testThreads.js",
133
+ "test/utils/perf-helper.js",
150
134
  "test/utils/runChatterboxTTS.js",
151
135
  "test/utils/runSupertonicTTS.js",
152
136
  "test/utils/runParlerTTS.js",
@@ -221,7 +205,7 @@
221
205
  },
222
206
  "dependencies": {
223
207
  "@qvac/error": "^0.1.0",
224
- "@qvac/infer-base": "^0.6.2",
208
+ "@qvac/infer-base": "^0.8.0",
225
209
  "@qvac/langdetect-text": "^0.1.2",
226
210
  "@qvac/logging": "^0.1.0",
227
211
  "bare-fs": "^4.5.6",
@@ -232,12 +216,24 @@
232
216
  "bare-stream": "^2.7.0",
233
217
  "bare-url": "^2.4.3"
234
218
  },
235
- "types": "index.d.ts",
236
219
  "optionalDependencies": {
237
- "@qvac/tts-ggml-linux-x64": "0.11.1",
238
- "@qvac/tts-ggml-linux-arm64": "0.11.1",
239
- "@qvac/tts-ggml-darwin-arm64": "0.11.1",
240
- "@qvac/tts-ggml-darwin-x64": "0.11.1",
241
- "@qvac/tts-ggml-win32-x64": "0.11.1"
220
+ "@qvac/tts-ggml-linux-x64": "0.13.0",
221
+ "@qvac/tts-ggml-linux-arm64": "0.13.0",
222
+ "@qvac/tts-ggml-darwin-arm64": "0.13.0",
223
+ "@qvac/tts-ggml-darwin-x64": "0.13.0",
224
+ "@qvac/tts-ggml-win32-x64": "0.13.0"
225
+ },
226
+ "types": "index.d.ts",
227
+ "peerDependencies": {
228
+ "@qvac/tts-ggml-android-arm64": "0.13.0",
229
+ "@qvac/tts-ggml-ios": "0.13.0"
230
+ },
231
+ "peerDependenciesMeta": {
232
+ "@qvac/tts-ggml-android-arm64": {
233
+ "optional": true
234
+ },
235
+ "@qvac/tts-ggml-ios": {
236
+ "optional": true
237
+ }
242
238
  }
243
239
  }