Pregunta

First of all, C++ is not my language (I'm a java programmer).

I've seen examples of Microsoft SAPI 5.1, and I need a way to print all the available voices in a machine. I've seen the Object token of SAPI, and I'm kinda confuse of how CComPtr is use to iterate through. Can anyone help me with this. Additionally, how can I pick a specific voice instead of using the default.

Based from the examples, you can get the default voice by invoking this codes:

ISpVoice * pVoice = NULL;

if (FAILED(::CoInitialize(NULL)))
    return FALSE;

HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);

So in short: How can I list all the voices available and how can I choose the voice?

//PS: I don't need to put it in a combo box (just like all examples that I've seen), I'm implementing this for a JNI dll library so an example of iteration is much preferred.

¿Fue útil?

Solución

First off, CComPtr is a smart pointer abstraction over COM interfaces, not an enumerator.

To list all the voices, you need to enumerate the tokens in the SPCAT_VOICES category.

HRESULT hr = S_OK;
CComPtr<ISpObjectTokenCategory> cpSpCategory = NULL; 
if (SUCCEEDED(hr = SpGetCategoryFromId(SPCAT_VOICES, &cpSpCategory))) 
{ 
    CComPtr<IEnumSpObjectTokens> cpSpEnumTokens; 
    if (SUCCEEDED(hr = cpSpCategory->EnumTokens(NULL, NULL, &cpSpEnumTokens))) 
   { 
        CComPtr<ISpObjectToken> pSpTok;
        while (SUCCEEDED(hr = cpSpEnumTokens->Next(1,&pSpTok, NULL)))) 
        {
            // do something with the token here; for example, set the voice
            pVoice->SetVoice(pSpTok,FALSE); 
            // NOTE:  IEnumSpObjectTokens::Next will *overwrite* the pointer; must manually release
            pSpTok.Release(); 
        }
   } 
} 

If you want to pick a specific voice, you need to specify an attribute that's unique to that voice. EnumTokens allows you to specify required and optional attributes. The attributes are actually defined by the creator of the voice, but some common attributes are

  • Name (e.g., "Microsoft Anna")
  • Language (specified by a numeric locale ID)
  • Gender (male/female)
  • Vendor (name of company that created the voice)

So to specify "Microsoft Anna" instead of any voice, you would use

if (SUCCEEDED(hr = cpSpCategory->EnumTokens(L"Name=Microsoft Anna", NULL, &cpSpEnumTokens))) 

instead of

if (SUCCEEDED(hr = cpSpCategory->EnumTokens(NULL, NULL, &cpSpEnumTokens))) 

Otros consejos

The enum method does work but is a little clunky. The best way is to open the registry and go through the keys and their attributes, you can find more information here:

msdn: SAPI Tokens, Categories and the Registry

Again that's a bit of work, so I've created an interface while doing something else and it may help you or somebody else:

Sapi interface for enumerating and searching voice tokens

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top