Would copying registry entries to get access to all installed TTS voices be against the MS TOS?

AlexS 45 Reputation points
2024-08-26T07:33:56.2533333+00:00

Hello,

I'm building an accessibility app that uses TTS voices already installed on a Windows 10/11 machine. However, GetInstalledVoices() provided by the SpeechSynthesizer class only gives me two options despite having installed German, English, and Dutch language packs. I need at least one voice per language to be available.

After some research, I discovered voices are registered at different registry locations: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices and HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices. Unfortunately, only the voices in the first location are accessible by the SpeechSynthesizer.

All solutions I can find for this suggest I copy the voices from one location to the other. However, I'm worried this might be against the Microsoft TOS.

Developer technologies | .NET | Other
Developer technologies | C#
{count} votes

Accepted answer
  1. Castorix31 90,686 Reputation points
    2024-08-26T09:19:25.77+00:00

    You don't need to copy registry keys with SpeechLib

    You can use SpObjectTokenCategory.SetId with the 2nd registry path to get the voices.

    Test :

    // Add reference to : Microsoft Speech Object Library (SAPI)
    

    At beginning :

    SpVoice voice = new SpVoice();
    

    Then :

    
    {
        ISpVoice pVoice = (ISpVoice)voice;
        SpObjectTokenCategory otc = new SpObjectTokenCategory();
        //otc.SetId("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices");
        otc.SetId("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices");
        ISpeechObjectTokens tokenEnum = otc.EnumerateTokens();
        int nTokenCount = tokenEnum.Count;
        Console.WriteLine("Number of voices: {0}", nTokenCount);
        foreach (ISpeechObjectToken sot in tokenEnum)
        {
            Console.WriteLine("Voice : {0}", sot.GetDescription());
            {
                pVoice.SetVoice((ISpObjectToken)sot);
                try
                {
                    uint n = 0;                       
                    pVoice.Speak("Hello! This is a test", 0, out n);                        
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine("Cannot speak with the voice : {0}", sot.GetDescription());
                }
                Marshal.ReleaseComObject(sot);
            }
        }
    }
    
    
    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.