Spaces:
Running
Running
v0.2 polish: per-voice default speeds + trailing audio pad
Browse files- voicepacks.json: Asha 0.85, Vivek 0.9, Mukta 0.9, Dnyanesh 0.9
(matches v0.1 Asha/Vivek natural-pace docs; SPRINGLab voices
sound natural at the same range per listening tests)
- main.ts: 80 ms trailing pad after last chunk's audio so ISTFTNet
output's final phoneme release transient isn't clipped at buffer
edge — fixes "last word eaten" perception across all voicepacks
- README.md +10 -9
- assets/index-B2DCZUEd.js +3 -0
- index.html +1 -1
- public/voicepacks.json +4 -4
- src/main.ts +12 -0
- voicepacks.json +4 -4
README.md
CHANGED
|
@@ -6,7 +6,6 @@ colorTo: red
|
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
| 9 |
-
short_description: Marathi TTS in the browser — Kokoro-82M fine-tune, WebGPU
|
| 10 |
models:
|
| 11 |
- shreyask/bol-tts-marathi-onnx
|
| 12 |
tags:
|
|
@@ -19,7 +18,7 @@ tags:
|
|
| 19 |
|
| 20 |
# bol-tts-marathi — Marathi TTS via WebGPU
|
| 21 |
|
| 22 |
-
In-browser Marathi (मराठी) text-to-speech, running real-time on WebGPU.
|
| 23 |
|
| 24 |
This Space ships **both the built demo** (`index.html` + `assets/` served directly) **and the full source** (`src/`, `package.json`, `tsconfig.json`, `vite.config.ts`) so anyone can fork the Space and rebuild without de-minifying the bundle.
|
| 25 |
|
|
@@ -28,7 +27,7 @@ This Space ships **both the built demo** (`index.html` + `assets/` served direct
|
|
| 28 |
| Path | Role |
|
| 29 |
|---|---|
|
| 30 |
| `index.html`, `assets/*` | built demo, served via static SDK |
|
| 31 |
-
| `voices/*.bin` |
|
| 32 |
| `voicepacks.json` | source-of-truth for voice list + per-gender test phrases |
|
| 33 |
| `src/` | TypeScript source (phonemizer, tokenizer, model wrapper, UI wiring) |
|
| 34 |
| `public/` | static assets fed to the build |
|
|
@@ -50,19 +49,21 @@ npm run build # produces dist/ — same artifacts shipped here
|
|
| 50 |
- 82M-parameter Kokoro fine-tune for Marathi (model: [`shreyask/bol-tts-marathi-onnx`](https://huggingface.co/shreyask/bol-tts-marathi-onnx))
|
| 51 |
- `@huggingface/transformers` loads the ONNX model into WebGPU (or falls back to WASM)
|
| 52 |
- `espeak-ng-wasm` phonemizes Marathi + Indian English; we parse `(en)/(mr)` tags for per-segment Indian-accent rules on English chunks
|
| 53 |
-
-
|
| 54 |
- Test phrases + voice metadata in `voicepacks.json` — edit to add voices, no code changes needed
|
| 55 |
|
| 56 |
Recipe + training scripts: [github.com/shreyaskarnik/bol-tts-marathi](https://github.com/shreyaskarnik/bol-tts-marathi)
|
| 57 |
|
| 58 |
## Voices
|
| 59 |
|
| 60 |
-
| ID | Name | Gender | Source |
|
| 61 |
|---|---|---|---|---|
|
| 62 |
-
| `mf_asha` | Asha (आशा) | female | Rasa Marathi |
|
| 63 |
-
| `mm_vivek` | Vivek (विवेक) | male | Rasa Marathi |
|
| 64 |
-
| `mf_mukta` | Mukta (मुक्ता) | female |
|
| 65 |
-
| `mm_dnyanesh` | Dnyanesh (ज्ञानेश) | male |
|
|
|
|
|
|
|
| 66 |
|
| 67 |
## License
|
| 68 |
|
|
|
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
|
|
|
| 9 |
models:
|
| 10 |
- shreyask/bol-tts-marathi-onnx
|
| 11 |
tags:
|
|
|
|
| 18 |
|
| 19 |
# bol-tts-marathi — Marathi TTS via WebGPU
|
| 20 |
|
| 21 |
+
In-browser Marathi (मराठी) text-to-speech, running real-time on WebGPU. Six voices, code-switch (Minglish) support, no server round-trip.
|
| 22 |
|
| 23 |
This Space ships **both the built demo** (`index.html` + `assets/` served directly) **and the full source** (`src/`, `package.json`, `tsconfig.json`, `vite.config.ts`) so anyone can fork the Space and rebuild without de-minifying the bundle.
|
| 24 |
|
|
|
|
| 27 |
| Path | Role |
|
| 28 |
|---|---|
|
| 29 |
| `index.html`, `assets/*` | built demo, served via static SDK |
|
| 30 |
+
| `voices/*.bin` | 6 voicepacks (style vectors, 522 KB each) |
|
| 31 |
| `voicepacks.json` | source-of-truth for voice list + per-gender test phrases |
|
| 32 |
| `src/` | TypeScript source (phonemizer, tokenizer, model wrapper, UI wiring) |
|
| 33 |
| `public/` | static assets fed to the build |
|
|
|
|
| 49 |
- 82M-parameter Kokoro fine-tune for Marathi (model: [`shreyask/bol-tts-marathi-onnx`](https://huggingface.co/shreyask/bol-tts-marathi-onnx))
|
| 50 |
- `@huggingface/transformers` loads the ONNX model into WebGPU (or falls back to WASM)
|
| 51 |
- `espeak-ng-wasm` phonemizes Marathi + Indian English; we parse `(en)/(mr)` tags for per-segment Indian-accent rules on English chunks
|
| 52 |
+
- 6 voices via single shared model + per-voice 256-D style vectors (`voices/*.bin`, [510, 1, 256] float32)
|
| 53 |
- Test phrases + voice metadata in `voicepacks.json` — edit to add voices, no code changes needed
|
| 54 |
|
| 55 |
Recipe + training scripts: [github.com/shreyaskarnik/bol-tts-marathi](https://github.com/shreyaskarnik/bol-tts-marathi)
|
| 56 |
|
| 57 |
## Voices
|
| 58 |
|
| 59 |
+
| ID | Name | Gender | Source | Status |
|
| 60 |
|---|---|---|---|---|
|
| 61 |
+
| `mf_asha` | Asha (आशा) | female | Rasa Marathi | stable |
|
| 62 |
+
| `mm_vivek` | Vivek (विवेक) | male | Rasa Marathi | stable |
|
| 63 |
+
| `mf_mukta` | Mukta (मुक्ता) | female | IndicVoices-R | stable |
|
| 64 |
+
| `mm_dnyanesh` | Dnyanesh (ज्ञानेश) | male | IndicVoices-R | stable |
|
| 65 |
+
| `mf_priya` | Priya (प्रिया) | female | SPRINGLab IndicTTS | v0.2 preview |
|
| 66 |
+
| `mm_arjun` | Arjun (अर्जुन) | male | SPRINGLab IndicTTS | v0.2 preview |
|
| 67 |
|
| 68 |
## License
|
| 69 |
|
assets/index-B2DCZUEd.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:730e27728d87c38794231d4bf98054a830d90a44af363bfb99fa9b49373d38b2
|
| 3 |
+
size 19064872
|
index.html
CHANGED
|
@@ -17,7 +17,7 @@
|
|
| 17 |
rel="stylesheet"
|
| 18 |
/>
|
| 19 |
|
| 20 |
-
<script type="module" crossorigin src="/assets/index-
|
| 21 |
<link rel="stylesheet" crossorigin href="/assets/index-BdhRcMoO.css">
|
| 22 |
</head>
|
| 23 |
<body>
|
|
|
|
| 17 |
rel="stylesheet"
|
| 18 |
/>
|
| 19 |
|
| 20 |
+
<script type="module" crossorigin src="/assets/index-B2DCZUEd.js"></script>
|
| 21 |
<link rel="stylesheet" crossorigin href="/assets/index-BdhRcMoO.css">
|
| 22 |
</head>
|
| 23 |
<body>
|
public/voicepacks.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
| 8 |
"name_native": "आशा",
|
| 9 |
"gender": "female",
|
| 10 |
"source": "rasa",
|
| 11 |
-
"default_speed":
|
| 12 |
"ship_status": "stable"
|
| 13 |
},
|
| 14 |
{
|
|
@@ -17,7 +17,7 @@
|
|
| 17 |
"name_native": "विवेक",
|
| 18 |
"gender": "male",
|
| 19 |
"source": "rasa",
|
| 20 |
-
"default_speed":
|
| 21 |
"ship_status": "stable"
|
| 22 |
},
|
| 23 |
{
|
|
@@ -26,7 +26,7 @@
|
|
| 26 |
"name_native": "मुक्ता",
|
| 27 |
"gender": "female",
|
| 28 |
"source": "springlab",
|
| 29 |
-
"default_speed":
|
| 30 |
"ship_status": "stable"
|
| 31 |
},
|
| 32 |
{
|
|
@@ -35,7 +35,7 @@
|
|
| 35 |
"name_native": "ज्ञानेश",
|
| 36 |
"gender": "male",
|
| 37 |
"source": "springlab",
|
| 38 |
-
"default_speed":
|
| 39 |
"ship_status": "stable"
|
| 40 |
}
|
| 41 |
],
|
|
|
|
| 8 |
"name_native": "आशा",
|
| 9 |
"gender": "female",
|
| 10 |
"source": "rasa",
|
| 11 |
+
"default_speed": 0.85,
|
| 12 |
"ship_status": "stable"
|
| 13 |
},
|
| 14 |
{
|
|
|
|
| 17 |
"name_native": "विवेक",
|
| 18 |
"gender": "male",
|
| 19 |
"source": "rasa",
|
| 20 |
+
"default_speed": 0.9,
|
| 21 |
"ship_status": "stable"
|
| 22 |
},
|
| 23 |
{
|
|
|
|
| 26 |
"name_native": "मुक्ता",
|
| 27 |
"gender": "female",
|
| 28 |
"source": "springlab",
|
| 29 |
+
"default_speed": 0.9,
|
| 30 |
"ship_status": "stable"
|
| 31 |
},
|
| 32 |
{
|
|
|
|
| 35 |
"name_native": "ज्ञानेश",
|
| 36 |
"gender": "male",
|
| 37 |
"source": "springlab",
|
| 38 |
+
"default_speed": 0.9,
|
| 39 |
"ship_status": "stable"
|
| 40 |
}
|
| 41 |
],
|
src/main.ts
CHANGED
|
@@ -476,6 +476,18 @@ async function onSynth() {
|
|
| 476 |
audioOffsetSamples += PAD_SAMPLES;
|
| 477 |
}
|
| 478 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 479 |
const t1 = performance.now();
|
| 480 |
|
| 481 |
// Concat audio into one Float32Array for the WAV encoder + waveform.
|
|
|
|
| 476 |
audioOffsetSamples += PAD_SAMPLES;
|
| 477 |
}
|
| 478 |
}
|
| 479 |
+
|
| 480 |
+
// Trailing pad after the final chunk. ISTFTNet decoder produces samples
|
| 481 |
+
// up to the last predicted phoneme's duration with no acoustic decay
|
| 482 |
+
// buffer — without this pad, the very end of the audio file ends mid-
|
| 483 |
+
// release-transient and listeners perceive the last word as "eaten".
|
| 484 |
+
// 80 ms is enough to cover any voicepack's natural release without
|
| 485 |
+
// making the end feel laggy.
|
| 486 |
+
const TRAIL_PAD_SEC = 0.08;
|
| 487 |
+
const TRAIL_PAD_SAMPLES = Math.floor(sampleRate * TRAIL_PAD_SEC);
|
| 488 |
+
allAudio.push(new Float32Array(TRAIL_PAD_SAMPLES));
|
| 489 |
+
audioOffsetSamples += TRAIL_PAD_SAMPLES;
|
| 490 |
+
|
| 491 |
const t1 = performance.now();
|
| 492 |
|
| 493 |
// Concat audio into one Float32Array for the WAV encoder + waveform.
|
voicepacks.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
| 8 |
"name_native": "आशा",
|
| 9 |
"gender": "female",
|
| 10 |
"source": "rasa",
|
| 11 |
-
"default_speed":
|
| 12 |
"ship_status": "stable"
|
| 13 |
},
|
| 14 |
{
|
|
@@ -17,7 +17,7 @@
|
|
| 17 |
"name_native": "विवेक",
|
| 18 |
"gender": "male",
|
| 19 |
"source": "rasa",
|
| 20 |
-
"default_speed":
|
| 21 |
"ship_status": "stable"
|
| 22 |
},
|
| 23 |
{
|
|
@@ -26,7 +26,7 @@
|
|
| 26 |
"name_native": "मुक्ता",
|
| 27 |
"gender": "female",
|
| 28 |
"source": "springlab",
|
| 29 |
-
"default_speed":
|
| 30 |
"ship_status": "stable"
|
| 31 |
},
|
| 32 |
{
|
|
@@ -35,7 +35,7 @@
|
|
| 35 |
"name_native": "ज्ञानेश",
|
| 36 |
"gender": "male",
|
| 37 |
"source": "springlab",
|
| 38 |
-
"default_speed":
|
| 39 |
"ship_status": "stable"
|
| 40 |
}
|
| 41 |
],
|
|
|
|
| 8 |
"name_native": "आशा",
|
| 9 |
"gender": "female",
|
| 10 |
"source": "rasa",
|
| 11 |
+
"default_speed": 0.85,
|
| 12 |
"ship_status": "stable"
|
| 13 |
},
|
| 14 |
{
|
|
|
|
| 17 |
"name_native": "विवेक",
|
| 18 |
"gender": "male",
|
| 19 |
"source": "rasa",
|
| 20 |
+
"default_speed": 0.9,
|
| 21 |
"ship_status": "stable"
|
| 22 |
},
|
| 23 |
{
|
|
|
|
| 26 |
"name_native": "मुक्ता",
|
| 27 |
"gender": "female",
|
| 28 |
"source": "springlab",
|
| 29 |
+
"default_speed": 0.9,
|
| 30 |
"ship_status": "stable"
|
| 31 |
},
|
| 32 |
{
|
|
|
|
| 35 |
"name_native": "ज्ञानेश",
|
| 36 |
"gender": "male",
|
| 37 |
"source": "springlab",
|
| 38 |
+
"default_speed": 0.9,
|
| 39 |
"ship_status": "stable"
|
| 40 |
}
|
| 41 |
],
|