host: volume option; docs: voice adjustments beyond speed (volume, Flextalk profile)
This commit is contained in:
@@ -46,7 +46,8 @@ Manual steps, if needed:
|
|||||||
setup/run.sh -v Sam -t "Hello." -o sam.wav
|
setup/run.sh -v Sam -t "Hello." -o sam.wav
|
||||||
setup/run.sh -v "Keith Bell" -t "Hello." -o keith.wav -p 100 -s 150
|
setup/run.sh -v "Keith Bell" -t "Hello." -o keith.wav -p 100 -s 150
|
||||||
|
|
||||||
Options: `-v` voice, `-t` text, `-o` output WAV, `-p` pitch, `-s` speed.
|
Options: `-v` voice, `-t` text, `-o` output WAV, `-p` pitch, `-s` speed, `-V` volume
|
||||||
|
(volume is engine-specific; not used by the Veskslop wrapper).
|
||||||
|
|
||||||
## Veskslop integration
|
## Veskslop integration
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,12 @@ final file `WatsonUNInstall.dll` is incomplete).
|
|||||||
Verified with the corrected DWORD registry: Kerry 0 st = 209 Hz, -6 st = 148 Hz,
|
Verified with the corrected DWORD registry: Kerry 0 st = 209 Hz, -6 st = 148 Hz,
|
||||||
+6 st = 250 Hz (clamped at max); Keith 0 st = 119 Hz, +6 st = 170 Hz.
|
+6 st = 250 Hz (clamped at max); Keith 0 st = 119 Hz, +6 st = 170 Hz.
|
||||||
- The wrapper maps semitones as `natural * 2^(st/12)` and clamps to the range.
|
- The wrapper maps semitones as `natural * 2^(st/12)` and clamps to the range.
|
||||||
|
- volume: available through `ITTSAttributes` (host flag `-V`). Flextalk is linear
|
||||||
|
(0-65535, default 65535; half is about -6 dB). MSTTS is non-linear (0 = silence,
|
||||||
|
4096 about -24 dB, 65535+ full scale); treat it as on/off.
|
||||||
|
- Flextalk per-speaker profile values are applied at voice load; `Expression` was
|
||||||
|
verified audible (0/59/100 produce different waveforms at equal duration). Changing
|
||||||
|
them requires a registry edit and re-selecting the voice.
|
||||||
|
|
||||||
## Decompiled corpora (Ghidra)
|
## Decompiled corpora (Ghidra)
|
||||||
|
|
||||||
|
|||||||
+28
-2
@@ -260,10 +260,36 @@ record what the engine needs to interpret, add, or hide._
|
|||||||
### Text handling
|
### Text handling
|
||||||
|
|
||||||
- SAPI4 is ANSI/CP1252. The wrapper converts UTF-8 to CP1252 and maps emoji and
|
- SAPI4 is ANSI/CP1252. The wrapper converts UTF-8 to CP1252 and maps emoji and
|
||||||
unmappable characters to spaces. Engine tag parsing is disabled, so input stays plain
|
unmappable characters to spaces. The host passes `TTSDATAFLAG_TAGGED`, so SAPI4 control
|
||||||
text (no SSML), matching the contract.
|
tags in the text are enabled at the engine level; tagged input is not part of this
|
||||||
|
contract and is untested. Plain text (no SSML) is the contract.
|
||||||
- Lines up to 1000 characters are well within engine limits.
|
- Lines up to 1000 characters are well within engine limits.
|
||||||
|
|
||||||
|
### Other voice adjustments (beyond speed)
|
||||||
|
|
||||||
|
All voices implement SAPI4 `ITTSAttributes`, so **pitch, speed and volume** exist at the
|
||||||
|
API level. The Veskslop contract exposes only speed and pitch; volume is available in the
|
||||||
|
host as `sapi4host -V <value>` and is not sent by Veskslop.
|
||||||
|
|
||||||
|
- **Volume** (measured 2026-09-15):
|
||||||
|
- Flextalk: linear, range 0-65535, default 65535; half (32767) is about -6 dB, 0 is
|
||||||
|
silence.
|
||||||
|
- MSTTS: default is 0xFFFFFFFF; 0 is silence, but the response is not linear (for
|
||||||
|
example 4096 gives about -24 dB while 65535 and larger are full scale). Treat volume
|
||||||
|
as effectively on/off for MSTTS.
|
||||||
|
- **Flextalk per-speaker profile** (applied at voice load, not runtime-adjustable):
|
||||||
|
values live in `HKLM\Software\AT&T\Watson\2.0\FlexTalk\2.0\Speakers\{GUID}` (see
|
||||||
|
`docs/NOTES.md` for the full list and defaults). `Pitch`/`Speaking Rate` set the natural
|
||||||
|
voice; **Expression** was verified to change the synthesis audibly (Keith Bell at
|
||||||
|
Expression 0 / 59 / 100 yields different waveforms with the same duration). Changing a
|
||||||
|
profile requires a registry edit and re-selecting the voice.
|
||||||
|
- **MSTTS voice character** is fixed by the `.vce`/`.cfg` data; the engine exposes no
|
||||||
|
per-voice profile in the registry. Its effect variants (telephone, in Hall, in Stadium,
|
||||||
|
in Space) are separate voice modes with separate data, exposed as distinct voice IDs
|
||||||
|
(`mike-telephone`, `mary-hall`, ...), not runtime effects.
|
||||||
|
- Not exposed by this integration: SSML, prosody/style tags, or SAPI4 attribute
|
||||||
|
extensions beyond pitch/speed/volume.
|
||||||
|
|
||||||
### Transport and latency
|
### Transport and latency
|
||||||
|
|
||||||
- Installation is one command: `setup/install.sh` (system dependencies with sudo, wine
|
- Installation is one command: `setup/install.sh` (system dependencies with sudo, wine
|
||||||
|
|||||||
+12
-3
@@ -157,7 +157,7 @@ static void usage(void)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: sapi4host -l\n"
|
"usage: sapi4host -l\n"
|
||||||
" sapi4host -v <voice> -t <text> -o <out.wav>"
|
" sapi4host -v <voice> -t <text> -o <out.wav>"
|
||||||
" [-p pitch] [-s speed]\n");
|
" [-p pitch] [-s speed] [-V volume]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
@@ -168,6 +168,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
const char *voice = NULL, *text = NULL, *out = NULL;
|
const char *voice = NULL, *text = NULL, *out = NULL;
|
||||||
int pitch = -1, speed = -1;
|
int pitch = -1, speed = -1;
|
||||||
|
long volume = -1;
|
||||||
int i;
|
int i;
|
||||||
TTSMODEINFO mode;
|
TTSMODEINFO mode;
|
||||||
|
|
||||||
@@ -182,6 +183,7 @@ int main(int argc, char **argv)
|
|||||||
else if (!strcmp(argv[i], "-o")) out = argv[++i];
|
else if (!strcmp(argv[i], "-o")) out = argv[++i];
|
||||||
else if (!strcmp(argv[i], "-p")) pitch = atoi(argv[++i]);
|
else if (!strcmp(argv[i], "-p")) pitch = atoi(argv[++i]);
|
||||||
else if (!strcmp(argv[i], "-s")) speed = atoi(argv[++i]);
|
else if (!strcmp(argv[i], "-s")) speed = atoi(argv[++i]);
|
||||||
|
else if (!strcmp(argv[i], "-V")) volume = strtol(argv[++i], NULL, 0);
|
||||||
else { usage(); return 2; }
|
else { usage(); return 2; }
|
||||||
}
|
}
|
||||||
if (!voice || !text || !out) { usage(); return 2; }
|
if (!voice || !text || !out) { usage(); return 2; }
|
||||||
@@ -257,9 +259,9 @@ int main(int argc, char **argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pitch and speed are optional: when unset, leave the engine's own
|
/* Pitch, speed and volume are optional: when unset, leave the engine's own
|
||||||
voice profile untouched (probing/setting would override it). */
|
voice profile untouched (probing/setting would override it). */
|
||||||
if (pitch >= 0 || speed >= 0) {
|
if (pitch >= 0 || speed >= 0 || volume >= 0) {
|
||||||
WORD pmin = 0, pmax = 0;
|
WORD pmin = 0, pmax = 0;
|
||||||
DWORD smin = 0, smax = 0;
|
DWORD smin = 0, smax = 0;
|
||||||
|
|
||||||
@@ -284,6 +286,13 @@ int main(int argc, char **argv)
|
|||||||
printf("speed: %d (%lu..%lu)\n",
|
printf("speed: %d (%lu..%lu)\n",
|
||||||
speed, (unsigned long)smin, (unsigned long)smax);
|
speed, (unsigned long)smin, (unsigned long)smax);
|
||||||
}
|
}
|
||||||
|
if (volume >= 0) {
|
||||||
|
DWORD vdef = 0;
|
||||||
|
attr->lpVtbl->VolumeGet(attr, &vdef);
|
||||||
|
attr->lpVtbl->VolumeSet(attr, (DWORD)volume);
|
||||||
|
printf("volume: %ld (default %lu)\n",
|
||||||
|
volume, (unsigned long)vdef);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user