# Notes ## Registry facts From `spchapi/SPCHAPI.INF` (`%49000%` = `%25%\speech` = `C:\windows\speech`): - `CLSID_TTSEnumerator` `{D67C0280-C743-11cd-80E5-00AA003E4B50}` -> `Speech.dll` - "Audio Destination to File Object" `{D4623720-E4B9-11cf-8D56-00A0C9034A7E}` -> `Speech.dll` - "Audio Destination Object" `{CB96B400-C743-11cd-80E5-00AA003E4B50}` -> `Speech.dll` - Lexicon dialog `{92655FB1-ADF9-11d1-BEB9-006008317CE8}` -> `Speech.dll` - Phoneme converter `{B9F11A96-90E3-11d0-8D77-00A0C9034A7E}` -> `Speech.dll` From `msttsl/mstts.inf` (`[TTSReg]`): - Engine `MSTTSSyn` = `{E0725551-286F-11d0-8E73-00A0C9083363}` -> `MSTTSSYN.dll` - Engine install dir: `Common Files\microsoft shared\SpeechEngines\TTS`. - Enumerates voices by scanning `*.vce` in its own directory. ## Flextalk registration (from the installer's `setup.ins`) - Engine value: `HKLM\Software\Voice\TextToSpeech\Engine` `"AT&T FlexTalk" = "{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}"` - Engine subkey (forces mode enumeration): `...\Engine\{FFE78E00-...}` with `Dirty = 1` (REG_DWORD). The runtime rewrites `Count` + `Mode0..N` and clears `Dirty` after enumerating. - `HKCR\CLSID\{FFE78E00-C69C-11CE-AEC1-0000C0E9CB87}\InprocServer32` = `\EngineDLLs\FlexTalk.dll`, `ThreadingModel = Apartment`. Also registered: `{778EAAE2-499F-11CF-B0BA-444553540000}` -> same DLL. - Directories: `HKLM\Software\AT&T\Watson\2.0\FlexTalk\2.0\Directories` `RootDirectory = C:\FlexTalk\`. - Dictionaries: `...\FlexTalk\2.0\Dictionaries`: `StandardDictionary="2 ft_sdict.dll"`, `ExceptionDictionary="0 ft_udict.dll"`, `HomographDictionary="1 ft_hgrap.dll"`, `ProperNameDictionary="3 ft_namsa.dll"`, `LetterToSoundDictionary="4 ft_l2s.dll"`. - Options: `...\FlexTalk\2.0\Options` `Gender=Male`, `SampleRate=11025`. - Speakers (per-voice settings; names come from these values). **All numeric values must be REG_DWORD**: with REG_SZ the engine reads garbage and synthesizes a monotone buzz (pitch fixed at max, pitch control dead). - `{11260610-C84A-11ce-AEC4-0000C0E9CB87}`: Mode Name / Speaker Name "Keith Bell", Pitch 27, Speaking Rate 33, Head Size 46, Expression 59, Lowering 40, Prominences 17, Age 30, Volume 100. - `{000031CB-3699-551F-AED0-6B4893382D57}`: "Kerry Watson", Pitch 65, Speaking Rate 32, Head Size 45, Expression 100, Lowering 40, Prominences 17, Age 30, Volume 100. - Voice data: `EngineData\AE1M08LC.*`, `AE1M11LC.*` (male, 8/11 kHz) and `AE2F08LC.*`, `AE2F11LC.*` (female); `.INV` inventory, `.NDX` index, `.COD` codebook, plus shared `DICT_CI.*`, `phondef`, `AMPRULES`, `ENDINGS`. Extraction: `unshield -O -d extracted x installer/flextalk/data1.cab` (`-O` = old compression; the archive.org package has no `data2.cab`, so the final file `WatsonUNInstall.dll` is incomplete). ## SAPI4 runtime engine discovery (`speech.dll`) - `FUN_635747a4` reads `HKLM\Software\Voice\TextToSpeech\Engine` values (value name = engine name, data = CLSID string), validates the GUID with `FUN_635712e4`, then opens a *subkey named by the CLSID string*. - `FUN_635758b1` (TTS mode-list ctor) reads `Dirty`; when non-zero/missing it calls `CoCreateInstance(CLSID, ..., IID @635791c0)` and pulls modes via vtable+0xC into 0xaf0-byte records, writes `Mode%d` (REG_BINARY), `Count`, then clears `Dirty`. When `Dirty=0` it reads the cached `Mode%d` blobs. - Practical rule: to add an engine, register the `Engine` value + the CLSID `InprocServer32` + an engine subkey with `Dirty=1` (a missing subkey also triggers enumeration). ## Environment gotchas - Wine needs a working X display (the runtime creates windows). `xvfb-run -a` proved flaky here; `setup/run.sh` starts a persistent `Xvfb :77` instead. - Wine reports `err:ole:apartment_add_dll couldn't load in-process dll` when the `InprocServer32` path does not exist. Check the file copy first (this bit us: a bad `unshield` run created empty directories). - 32-bit engines require a 32-bit prefix (`WINEARCH=win32`). - `sudo` on this machine requires a password; installs are manual. ## Engine units (measured) - speed: MSTTS range 30-450, Flextalk 50-390; the natural rate is about 150 for every voice (duration at 100/200/300 fits a natural value near 140-150). - pitch: engine units, roughly linear in F0 near the natural point (~1.1 Hz per unit). Natural values: about 100 (MSTTS), 106 (Keith Bell), 186 (Kerry Watson); Flextalk max 250. 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. - 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) - `/mnt/ghidra/decomp/msttssyn.dll/` (786 functions, engine) - `/mnt/ghidra/decomp/speech.dll/` (1030 functions, SAPI4 runtime)