// Parameters // p_voice : The string to set the voice to // Returns // true if setting the voice succeeded, false otherwise. // Description // Lists the available voice tokens and iterates through them comparing each to p_voice. // If a token is found that matches p_voice then the voice is set to that token. If p_voice // doesn't match any of the voices available then returns false, and if setting the voice to // the matching token fails then also returns false. bool WindowsSAPI5Narrator::SetVoice(const char* p_voice) { USES_CONVERSION; if(!bInited) return false; bool t_success = true; const WCHAR *t_wvoice = A2W(p_voice); CComPtr<IEnumSpObjectTokens> cpEnum;// Pointer to token enumerator ULONG ulIndex = 0, ulCurTokenIndex = 0, ulNumTokens = 0; // Find out which token corresponds to our voice which is currently in use ISpObjectToken *pToken = NULL; // Token interface pointer t_success = _EnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum); if (t_success) t_success = SUCCEEDED(cpEnum->GetCount( &ulNumTokens )); if (t_success) t_success = ulNumTokens > 0; while (t_success && cpEnum->Next(1, &pToken, NULL) == S_OK) { CSpDynamicString ppcDesciptionString; // Get a string which describes the token, in our case, the voice name t_success = _GetDescription( pToken, &ppcDesciptionString); // Release the token itself pToken->Release(); pToken = NULL; if (t_success) { if(wcscmp(ppcDesciptionString, t_wvoice) == 0) { ulCurTokenIndex = ulIndex; break; } ulIndex++; } } if (t_success) t_success = ulIndex < ulNumTokens; if (t_success) { cpEnum->Item( ulCurTokenIndex, &pToken ); t_success = SUCCEEDED(m_cpVoice->SetVoice( pToken )); pToken->Release(); } return t_success; }
HRESULT LoadVoices(void){ HRESULT hr; ISpObjectToken *pToken; IEnumSpObjectTokens *cpEnum; wchar_t *pDescription, *p, *ptr, szBuffer[64]; hr = _EnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum); if(hr == S_OK){ g_VoicesCount = 0; pDescription = (wchar_t *)CoTaskMemAlloc(128 * sizeof(wchar_t)); while(IEnumSpObjectTokens_Next(cpEnum, 1, &pToken, NULL) == S_OK){ hr = _GetDescription(pToken, &pDescription); if(SUCCEEDED(hr)){ g_VoicesCount++; wcscpy(g_PVoices[g_VoicesCount - 1].name, pDescription); g_PVoices[g_VoicesCount - 1].token = pToken; GetPrivateProfileStringW(S_VOICES, pDescription, NULL, szBuffer, 64, g_NotePaths.INIFile); if(*szBuffer){ p = wcstok(szBuffer, L"|", &ptr); g_PVoices[g_VoicesCount - 1].rate = _wtol(p); p = wcstok(NULL, L"|", &ptr); g_PVoices[g_VoicesCount - 1].volume = (unsigned short)_wtoi(p); g_PVoices[g_VoicesCount - 1].pitch = (short)_wtoi(ptr); } else{ ISpVoice *pVoice = CreateVoice(); ISpVoice_SetVoice(pVoice, (ISpObjectToken *)g_PVoices[g_VoicesCount - 1].token); ISpVoice_GetVolume(pVoice, &g_PVoices[g_VoicesCount - 1].volume); ISpVoice_GetRate(pVoice, &g_PVoices[g_VoicesCount - 1].rate); g_PVoices[g_VoicesCount - 1].pitch = 0; ReleaseVoice(pVoice); } if(g_VoicesCount == NELEMS(g_PVoices)) break; } if (FAILED(hr)) { ISpObjectToken_Release(pToken); break; } } CoTaskMemFree(pDescription); } else { hr = SPERR_NO_MORE_ITEMS; } return hr; }
// Returns // true if listing voices suceeeded, false otherwise. // Description // Iterates through the appropriate available voices and calls p_callback to return each voice. // If p_gender is kNarratorGenderMale then only male voices are returned, if p_gender is kNarratorGenderFemale // then only female voices are returned, otherwise all voices are returned. Can return false either if unable // to get a token enumerator for the voices or if out of memory when listing voices. bool WindowsSAPI5Narrator::ListVoices(NarratorGender p_gender, NarratorListVoicesCallback p_callback, void* p_context) { bool t_success = true; USES_CONVERSION; if(!bInited) return false; ISpObjectToken *pToken = NULL; // Token interface pointer CComPtr<IEnumSpObjectTokens> cpEnum;// Pointer to token enumerator ULONG ulIndex = 0; CSpDynamicString* ppcDesciptionString; ppcDesciptionString = NULL; WCHAR** ppszTokenIds; ppszTokenIds = NULL; ULONG ulNumTokens; WCHAR *szRequiredAttributes = NULL; // Set the required attributes field for the enum if we have special needs // based on our LPARAM in if (p_gender == kNarratorGenderMale) { szRequiredAttributes = L"Gender=Male"; } else if (p_gender == kNarratorGenderFemale) { szRequiredAttributes = L"Gender=Female"; } else if (p_gender == kNarratorGenderNeuter) { szRequiredAttributes = L"Gender=Neutral"; } // Get a token enumerator for tts voices available t_success = _EnumTokens(SPCAT_VOICES, szRequiredAttributes, NULL, &cpEnum); if (t_success) { t_success = SUCCEEDED(cpEnum->GetCount( &ulNumTokens )); if ( t_success && 0 != ulNumTokens ) { ppcDesciptionString = new CSpDynamicString [ulNumTokens]; if ( NULL == ppcDesciptionString ) { /* TODO - CLEANUP */ return false; } ppszTokenIds = new WCHAR* [ulNumTokens]; if ( NULL == ppszTokenIds ) { /* TODO - CLEANUP */ return false; } ZeroMemory( ppszTokenIds, ulNumTokens*sizeof( WCHAR* ) ); // Get the next token in the enumeration // State is maintained in the enumerator while (t_success && cpEnum->Next(1, &pToken, NULL) == S_OK) { // Get a string which describes the token, in our case, the voice name t_success = SUCCEEDED(_GetDescription( pToken, &ppcDesciptionString[ulIndex] )); // Get the token id, for a low overhead way to retrieve the token later // without holding on to the object itself if (t_success) t_success = SUCCEEDED(pToken->GetId( &ppszTokenIds[ulIndex] )); ulIndex++; // Release the token itself pToken->Release(); pToken = NULL; } } // if we've failed to properly initialize, then we should completely shut-down if ( !t_success ) { if ( pToken ) { pToken->Release(); } ppszTokenIds = NULL; ppcDesciptionString = NULL; ulNumTokens = 0; } for ( ulIndex = 0; ulIndex < ulNumTokens; ulIndex++ ) { const char* string = W2A(ppcDesciptionString[ulIndex]); p_callback(p_context, p_gender, (const char *)string); } ManageCleanup( ppszTokenIds, ppcDesciptionString, ulNumTokens ); } return t_success; }