Windows 10. I've installed the Japanese TTS voices in the Settings. Now, when I use voice enumeration in Speech API 5.4 OneCore (not in 5.4 proper though), I get 6 voices:
- David
- Zira
- Ayumi
- Haruka
- Mark
- Ichiro
The Speech settings page also shows those 6. But there's clearly a seventh one in the registry, Sayaka (HKLM\SOFTWARE\WOW6432Node\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_jaJP_SayakaM
). Its files are present under C:\windows\Speech_OneCore\Engines\TTS\ja-JP
. Compared to the rest, there's an extra file, .heq
. Why doesn't it enumerate?
The enumeration code goes:
#import "libid:E6DA930B-BBA5-44DF-AC6F-FE60C1EDDEC8" rename_namespace("SAPI") //v5.4 OneCore
HRESULT hr;
SAPI::ISpVoicePtr v;
v.CreateInstance(__uuidof(SAPI::SpVoice));
SAPI::ISpObjectTokenPtr tok;
hr = v->GetVoice(&tok); //Retrieve the default voice
SAPI::ISpObjectTokenCategoryPtr cat;
hr = tok->GetCategory(&cat); //Retrieve the voices category
SAPI::IEnumSpObjectTokensPtr toks;
hr = cat->EnumTokens(0, 0, &toks);
//And enumerate
unsigned long i, n;
hr = toks->GetCount(&n);
LPWSTR ws;
for (i = 0; i < n; i++)
{
hr = toks->Item(i, &tok);
hr = tok->GetId(&ws);
CoTaskMemFree(ws);
}
The only other mention of Sayaka online that I could find is here
Edit
Enumerating by Reset()/Next() gives the same 6. Trying to create a token directly around the registry path gives error 0x8004503a (SPERR_NOT_FOUND
). Doing so while watching with Process Monitor reveals an interesting fact: rather than Sayaka under HKLM, the process interrogates the following key:
HKCU\Software\Microsoft\Speech_OneCore\Isolated\7WUiMB20NMV5Y7TgZ2WJXbUw32iGZQSvSkeaf0AevtQ\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens\MSTTS_V110_jaJP_SayakaM
There's indeed a key like that under HKCU, and it contains a copy of HKLM and HKCU settings for SAPI, and there's indeed no Sayaka under Voices in that key. Just the six I've mentioned.
So there's some kind of isolation going on, with SAPI settings in several copies. There are 7 different subkeys under Isolated
, and the voice sets are different under those. Two contain voices that have nothing in common with the ones we know, and those have to do with Cortana. Hard to tell what's the unit of isolation - maybe a user, maybe an app package (in the UWP sense).
Edit
Like I suspected, there's an app package based isolation going on. I've created a brand new project with the same code, ran it, and got a different isolation key - F2yLLxINh6S1e3y3MkJo4ilfh036RB_9pHLEVL88yL0
. Looks like every time you run a SAPI enabled application, it derives an isolation profile from the current executable. A moment ago, that isolation profile wasn't there, now it is. So it was created by SAPI on the fly. I don't think the voices are hard-coded, so it copied the voices in the isolation profile from somewhere, from the master list.
Where is the master list? It's not HKLM\...\Speech_OneCore
, since one can see Sayaka is there. It could be tokens_TTS_ja-JP.xml
under C:\Windows\SysWOW64\Speech_OneCore\Common\ja-JP
, since Ayumi/Ichiro/Haruka are listed there but Sayaka isn't. The security on that file is quite draconian though, I'm having trouble editing that file even with admin rights. Also, it's a second hardlink to C:\Windows\WinSxS\wow64_microsoft-windows-t..peech-ja-jp-onecore_31bf3856ad364e35_10.0.18362.1_none_46741f8a666da90a
.
The SysWOW64\Speech_OneCore
folder allows write for administrators, but SysWOW64\Speech_OneCore\Common
doesn't. Only TrustedInstaller can write it.
By the way, the isolation logic is specific to OneCore. SetId()
in SAPI 5.4 proper looks in the key that matches the provided Id
.
Alternative approach: the SAPI 5.4 docs mention the ISpRegDataKey interface, that lets one initialize a token directly from a HKEY. It's not in the typelib though.