'Windows 10 TTS voices not showing up?

I installed a few English language packs (US, UK and Canada) with their Speech options and I can access them in Windows 10 setting -> Speech but they doesn't show into text to speech option available from control panel and I can't use the voices with apps !

I can just use default voices which are David and Zira !

Any idea how can I use other voices ?



Solution 1:[1]

Windows 10 has two different TTS engines installed by default. There are the WinRT speech synthesis APIs (in the Windows.Media.SpeechSynthesis namespace), and the SAPI speech synthesis APIs (in the System.Speech.Synthesis namespace, and the COM ISpVoice interface).

David and Zira are SAPI voices; the language packs install WinRT voices.

The SAPI APIs and voices are legacy APIs, and are not being further developed; all new voices and effort are going into the WinRT APIs and voices.

If you want to use the language pack voices, you'll need to move your application over to WinRT and use the WinRT APIs.

Solution 2:[2]

I managed to fix this issue by modifying the Windows registry. In my case, under Windows 10, I installed the German language with TTS package and it installed a female voice (WinRT and SAPI) plus a male voice (WinRT only). I needed to make a desktop (not universal app) program in C# that utilized the male voice but it was not available through SAPI. So I did this "hack" and surprisingly worked right away (Windows 10 version 1803). Works for 32 and 64 bit programs (natively or WOW).

In Windows 8+ there are two speech synthesis programming interfaces (like explained by Eric Brown). But after studying the Windows registry and a couple of files referenced in there, I noticed that both APIs use the same data files so I copied the registry keys from the German male voice registered in WinRT API into the corresponding SAPI section.

Here are the detailed instructions:

  1. Open "regedit.exe".
  2. Navigate to the key

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens

There you will find each WinRT voice registered under its own key. The German male voice in my case is called MSTTS_V110_deDE_StefanM.

  1. The easiest thing is to right click the voice key (MSTTS_V110_deDE_StefanM) and from the context menu select Export to save the entire voice structure to a file (this will later allow you to easily replicate all these steps into a couple of clicks if you want to do this in another computer).

  2. Open the exported file with Notepad or similar. There you will find two key paths. Both will make a reference to the key Speech_OneCore. All you have to do is change both references from Speech_OneCore to Speech.

  3. Remove the entire line for the attributed called SayAsSupport, it is not needed by SAPI.

  4. Save your file. With the modifications it should look like this (take special notice to the key paths):

.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSTTS_V110_deDE_StefanM]
@="Microsoft Stefan - German (Germany)"
"407"="Microsoft Stefan - German (Germany)"
"CLSID"="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}"
"LangDataPath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,\
  00,70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,\
  65,00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,\
  00,5c,00,64,00,65,00,2d,00,44,00,45,00,5c,00,4d,00,53,00,54,00,54,00,53,00,\
  4c,00,6f,00,63,00,64,00,65,00,44,00,45,00,2e,00,64,00,61,00,74,00,00,00
"VoicePath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,\
  70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,65,\
  00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,00,\
  5c,00,64,00,65,00,2d,00,44,00,45,00,5c,00,4d,00,31,00,30,00,33,00,31,00,53,\
  00,74,00,65,00,66,00,61,00,6e,00,00,00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSTTS_V110_deDE_StefanM\Attributes]
"Age"="Adult"
"DataVersion"="11.0.2013.1022"
"Gender"="Male"
"Language"="407"
"Name"="Microsoft Stefan"
"SharedPronunciation"=""
"Vendor"="Microsoft"
"Version"="11.0"
  1. Embed the registry keys you created by double clicking the file.

Done! but please note that this will make the voice available through SAPI to 32 bit programs under a 32 bit version of Windows 10, OR, to 64 bit programs under a 64 bit version of Windows 10. If you want to access the voice from a 32 bit program under a 64 bit version of Windows 10 then you need to embed the corresponding keys under the WOW6432Node. To do this, simply make an extra copy of your already edited file and name it something like "my_voice_WOW.reg". Edit this new copy and now in both key paths insert another key named "WOW6432Node" between the keys SOFTWARE and Microsoft. Save your file and embed it, this should create the corresponding keys in the WOW tree-node. Your WOW file should look like this (take special notice to the key paths):

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Speech\Voices\Tokens\MSTTS_V110_deDE_StefanM]
@="Microsoft Stefan - German (Germany)"
"407"="Microsoft Stefan - German (Germany)"
"CLSID"="{179F3D56-1B0B-42B2-A962-59B7EF59FE1B}"
"LangDataPath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,\
  00,70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,\
  65,00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,\
  00,5c,00,64,00,65,00,2d,00,44,00,45,00,5c,00,4d,00,53,00,54,00,54,00,53,00,\
  4c,00,6f,00,63,00,64,00,65,00,44,00,45,00,2e,00,64,00,61,00,74,00,00,00
"VoicePath"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,53,00,\
  70,00,65,00,65,00,63,00,68,00,5f,00,4f,00,6e,00,65,00,43,00,6f,00,72,00,65,\
  00,5c,00,45,00,6e,00,67,00,69,00,6e,00,65,00,73,00,5c,00,54,00,54,00,53,00,\
  5c,00,64,00,65,00,2d,00,44,00,45,00,5c,00,4d,00,31,00,30,00,33,00,31,00,53,\
  00,74,00,65,00,66,00,61,00,6e,00,00,00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Speech\Voices\Tokens\MSTTS_V110_deDE_StefanM\Attributes]
"Age"="Adult"
"DataVersion"="11.0.2013.1022"
"Gender"="Male"
"Language"="407"
"Name"="Microsoft Stefan"
"SharedPronunciation"=""
"Vendor"="Microsoft"
"Version"="11.0"

Hope this helps.

Solution 3:[3]

This is a c# code example for copy the Speech_OnceCore Registry entry to Speech Registry entry (to be used with System.Speech.Synthesis as SAPI Voice):

public List<string> CopySpeechRegistryEntryFromOneCore()
{
    var voices = new List<string>();
    try
    {
        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens"))
        using (RegistryKey newKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Speech\Voices\Tokens", 
            RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl))
        {
            if (key != null)
            {
                var keys = key.GetSubKeyNames();
                foreach (var item in keys)
                {
                    if (newKey.OpenSubKey(item) == null)
                    {
                        RegistryKey voice = newKey.CreateSubKey(item);
                        foreach (var subKey in key.OpenSubKey(item).GetValueNames())
                        {
                            var value = key.OpenSubKey(item).GetValue(subKey);
                            if (value is string) value = (value as string).Replace(@"C:\WINDOWS", "%windir%");
                            var kind = key.OpenSubKey(item).GetValueKind(subKey);
                            voice.SetValue(subKey, value, kind);
                        }
                        foreach (var subAttribute in key.OpenSubKey(item).GetSubKeyNames())
                        {
                            RegistryKey attributes = voice.CreateSubKey(subAttribute);
                            foreach (var attribute in key.OpenSubKey(item).OpenSubKey(subAttribute).GetValueNames())
                            {
                                var value = key.OpenSubKey(item).OpenSubKey(subAttribute).GetValue(attribute);
                                var kind = key.OpenSubKey(item).OpenSubKey(subAttribute).GetValueKind(attribute);
                                if (attribute != "SayAsSupport")
                                {
                                    attributes.SetValue(attribute, value, kind);
                                }
                            }
                        }
                        voices.Add(item);
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        voices.Add($"Error: {ex.Message}");
        return voices;
    }
    return voices;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Eric Brown
Solution 2 Heinz
Solution 3 user2996563