// need to figure out how to do this specifically bool CSpeechSynthesizer::SetVoice(std::string* name) { // if we're not initialized return false if (!m_initialized) return false; bool result = false; TCHAR lang[13] = { 0 }; CComPtr<IEnumSpObjectTokens> cpIEnumeration; for (std::map<std::string*, std::string*>::iterator mit = m_tokenMap->begin(); mit != m_tokenMap->end(); mit++) { if (strcmp((*mit).first->c_str(), name->c_str()) == 0) { // Enumerate voice tokens const char* text = (*mit).second->c_str(); int size_needed = MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), NULL, 0); TCHAR tokenId[1024] = { 0 }; MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), &tokenId[0], size_needed); CComPtr<ISpObjectToken> cpTokenObj; HRESULT hr = SpGetTokenFromId(tokenId, &cpTokenObj, false); if (SUCCEEDED(hr)) { result = resetVoice((*mit).second); } break; } } return result; }
static void on_voice_combobox_changed(GtkComboBox *combobox, WCHAR** ppszTokenIds) { configure_changed = true; gint index = gtk_combo_box_get_active(combobox); if (ppszTokenIds && ppszTokenIds[index]) { ISpObjectToken *pToken; if (SpGetTokenFromId(ppszTokenIds[index] , &pToken) == S_OK) { pVoice->SetVoice(pToken); pToken->Release(); } } }
DLLIMPORT bool stardict_tts_plugin_init(StarDictTtsPlugInObject *obj) { if (FAILED(::CoInitialize(NULL))) return true; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if(!SUCCEEDED(hr)) { ::CoUninitialize(); return true; } std::string res = get_cfg_filename(); if (!g_file_test(res.c_str(), G_FILE_TEST_EXISTS)) { g_file_set_contents(res.c_str(), "[sapi_tts]\nvoice=\nvolume=100\nrate=0\n", -1, NULL); } GKeyFile *keyfile = g_key_file_new(); g_key_file_load_from_file(keyfile, res.c_str(), G_KEY_FILE_NONE, NULL); gchar *text = g_key_file_get_string(keyfile, "sapi_tts", "voice", NULL); if (text) { if (text[0] != '\0') { DWORD dwNum = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); wchar_t *pwText; pwText = new wchar_t[dwNum]; MultiByteToWideChar(CP_UTF8, 0, text, -1, pwText, dwNum); ISpObjectToken *pToken; if (SpGetTokenFromId(pwText , &pToken) == S_OK) { pVoice->SetVoice(pToken); pToken->Release(); } delete []pwText; } g_free(text); } GError *err; err = NULL; USHORT volume = g_key_file_get_integer(keyfile, "sapi_tts", "volume", &err); if (err) { g_error_free (err); volume = 100; } err = NULL; long rate = g_key_file_get_integer(keyfile, "sapi_tts", "rate", &err); if (err) { g_error_free (err); rate = 0; } g_key_file_free(keyfile); pVoice->SetVolume(volume); pVoice->SetRate(rate); obj->saytext_func = saytext; obj->tts_name = _("SAPI TTS"); g_print(_("SAPI tts plug-in loaded.\n")); return false; }
std::list<std::string*>* CSpeechSynthesizer::GetAvailableVoices() { std::list<std::string*>* namelist = new std::list<std::string*>(); // if we're not initialized return an empty list if (!m_initialized) return namelist; if (m_tokenMap->size() < 1) { for (std::map<std::string*, std::string*>::iterator mit = m_registryList->begin(); mit != m_registryList->end(); mit++) { std::string regToken = (*mit).first->c_str(); regToken.append("\\"); regToken.append((*mit).second->c_str()); // Enumerate voice tokens const char* text = regToken.c_str(); int size_needed = MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), NULL, 0); TCHAR tokenId[1024] = { 0 }; MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), &tokenId[0], size_needed); CComPtr<ISpObjectToken> cpTokenObj; HRESULT hr = SpGetTokenFromId(tokenId, &cpTokenObj, false); if (SUCCEEDED(hr)) { wchar_t* desc = new wchar_t[256]; SpGetDescription(cpTokenObj, &desc); char desctext[256] = { 0 }; wcstombs(desctext, desc, 256); std::string* voiceName = new std::string(desctext); namelist->push_back(voiceName); m_tokenMap->insert(std::pair<std::string*, std::string*>(voiceName, new std::string(regToken.c_str()))); } if (cpTokenObj != NULL) cpTokenObj.Release(); } } else { for (std::map<std::string*, std::string*>::iterator mit = m_tokenMap->begin(); mit != m_tokenMap->end(); mit++) { namelist->push_back((*mit).first); } } return namelist; }
bool CSpeechSynthesizer::resetVoice(std::string* name) { cpVoice.Release(); cpToken.Release(); cpIEnum.Release(); CoInitialize(cpIEnum); bool isServerVoice = name->find("Server"); // Create a voice and set its token to the one we just found. const char* text = name->c_str(); int size_needed = MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), NULL, 0); TCHAR tokenId[1024] = { 0 }; MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)strlen(text), &tokenId[0], size_needed); HRESULT hr = SpGetTokenFromId(tokenId, &cpToken, false); if (SUCCEEDED(hr)) { if (isServerVoice) hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&cpVoice); else hr = cpVoice.CoCreateInstance(CLSID_SpVoice); } // Set the voice. if (SUCCEEDED(hr)) { hr = cpVoice->SetVoice(cpToken); } // Set the output to the default audio device. if (SUCCEEDED(hr)) { hr = cpVoice->SetOutput(NULL, TRUE); } return SUCCEEDED(hr); }
/****************************************************************************** * ManageEmployeesPaneProc * *-------------------------* * Description: * Handles messages specifically for the manage employees pane. * ******************************************************************************/ LRESULT ManageEmployeesPaneProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { static ULONG ulNumTokens; static ULONG ulCurToken; static WCHAR** ppszTokenIds; static CSpDynamicString* ppcDescriptionString; // This is string helper class in sphelper.h static UINT iCurEnum; // Indicates if we should list males, females, or both switch ( message ) { case WM_GOTOOFFICE: { // Set the right message handler and repaint g_fpCurrentPane = OfficePaneProc; //Cleanup our variables ManageEmployeesPaneCleanup( ppszTokenIds, ppcDescriptionString, ulNumTokens ); ppszTokenIds = NULL; ppcDescriptionString = NULL; ulNumTokens = 0; // Set the hear voice rule to inactive HRESULT hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( VID_OtherRules, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( DYN_TTSVOICERULE, SPRS_ACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); PostMessage( hWnd, WM_INITPANE, NULL, NULL ); InvalidateRect( hWnd, NULL, TRUE ); return ( 1 ); } case WM_GOTOCOUNTER: { // Set the right message handler and repaint g_fpCurrentPane = CounterPaneProc; //Cleanup our variables ManageEmployeesPaneCleanup( ppszTokenIds, ppcDescriptionString, ulNumTokens ); ppszTokenIds = NULL; ppcDescriptionString = NULL; ulNumTokens = 0; // Set the hear voice rule to inactive HRESULT hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( VID_OtherRules, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( DYN_TTSVOICERULE, SPRS_ACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); PostMessage( hWnd, WM_INITPANE, NULL, NULL ); InvalidateRect( hWnd, NULL, TRUE ); return ( 1 ); } case WM_PAINT: { // Do the actual UI paint ManageEmployeesPanePaint( hWnd, ulNumTokens, ppcDescriptionString, ulCurToken, iCurEnum ); return ( 1 ); } case WM_INITPANE: { ISpObjectToken *pToken = NULL; // Token interface pointer CComPtr<IEnumSpObjectTokens> cpEnum; // Pointer to token enumerator ULONG ulIndex = 0; ulCurToken = 0xffffffff; WCHAR *szRequiredAttributes = NULL; SPSTATEHANDLE hDynamicRuleHandle; // Handle to our dynamic rule // Set the required attributes field for the enum if we have special needs // based on our LPARAM in if ( 0 == lParam ) { szRequiredAttributes = L"Gender=Male"; } else if ( 1 == lParam ) { szRequiredAttributes = L"Gender=Female"; } // Get a token enumerator for tts voices available HRESULT hr = SpEnumTokens(SPCAT_VOICES, szRequiredAttributes, NULL, &cpEnum); if ( S_OK == hr ) { // Get the numbers of tokens found hr = cpEnum->GetCount( &ulNumTokens ); if ( SUCCEEDED( hr ) && 0 != ulNumTokens ) { // Create arrays we need for storing data ppcDescriptionString = new CSpDynamicString [ulNumTokens]; if ( NULL == ppcDescriptionString ) { break; } ppszTokenIds = new WCHAR* [ulNumTokens]; if ( NULL == ppszTokenIds ) { break; } ZeroMemory( ppszTokenIds, ulNumTokens*sizeof( WCHAR* ) ); // Get the next token in the enumeration // State is maintained in the enumerator while (cpEnum->Next(1, &pToken, NULL) == S_OK) { // Get a string which describes the token, in our case, the voice name hr = SpGetDescription( pToken, &ppcDescriptionString[ulIndex] ); _ASSERTE( SUCCEEDED( hr ) ); // Get the token id, for a low overhead way to retrieve the token later // without holding on to the object itself hr = pToken->GetId( &ppszTokenIds[ulIndex] ); _ASSERTE( SUCCEEDED( hr ) ); ulIndex++; // Release the token itself pToken->Release(); pToken = NULL; } } // if we've failed to properly initialize, then we should completely shut-down if ( S_OK != hr ) { if ( pToken ) { pToken->Release(); } ManageEmployeesPaneCleanup( ppszTokenIds, ppcDescriptionString, ulNumTokens ); ppszTokenIds = NULL; ppcDescriptionString = NULL; ulNumTokens = 0; } // Find out which token corresponds to our voice which is currently in use else { WCHAR *pszCurTokenId = NULL; // Get the token representing the current voice hr = g_cpVoice->GetVoice( &pToken ); if ( SUCCEEDED( hr ) ) { // Get the current token ID, and compare it against others to figure out // which description string is the one currently selected. hr = pToken->GetId( &pszCurTokenId ); if ( SUCCEEDED( hr ) ) { ulIndex = 0; while ( ulIndex < ulNumTokens && 0 != _wcsicmp( pszCurTokenId, ppszTokenIds[ulIndex] ) ) { ulIndex++; } // We found it, so set the current index to that of the current token if ( ulIndex < ulNumTokens ) { ulCurToken = ulIndex; } CoTaskMemFree( pszCurTokenId ); } pToken->Release(); } } } // Initially, we see both genders _ASSERTE( lParam >= 0 && lParam <= 2); iCurEnum = (UINT)lParam; // Create a dynamic rule containing the description strings of the voice tokens hr = g_cpCmdGrammar->GetRule(NULL, DYN_TTSVOICERULE, SPRAF_TopLevel | SPRAF_Active | SPRAF_Dynamic, TRUE, &hDynamicRuleHandle); if ( SUCCEEDED( hr ) ) { // Clear the rule first hr = g_cpCmdGrammar->ClearRule( hDynamicRuleHandle ); _ASSERTE( SUCCEEDED( hr ) ); // Commit the changes hr = g_cpCmdGrammar->Commit(0); _ASSERTE( SUCCEEDED( hr ) ); // Add description names as the word, ulIndex as id for ( ulIndex = 0; ulIndex < ulNumTokens; ulIndex++ ) { SPPROPERTYINFO prop; prop.pszName = L"Id"; prop.pszValue = L"Property"; prop.vValue.vt = VT_I4; prop.vValue.ulVal = ulIndex; hr = g_cpCmdGrammar->AddWordTransition( hDynamicRuleHandle, NULL, ppcDescriptionString[ulIndex], L" ", SPWT_LEXICAL, 1.0, &prop); _ASSERTE( SUCCEEDED( hr ) ); } // Commit the changes hr = g_cpCmdGrammar->Commit(0); _ASSERTE( SUCCEEDED( hr ) ); // Set the dynamic rules to active hr = g_cpCmdGrammar->SetRuleIdState( DYN_TTSVOICERULE, SPRS_ACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); } // Set the hear voice rule to active hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_ACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( VID_OtherRules, SPRS_ACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); InvalidateRect( hWnd, NULL, TRUE ); return ( 1 ); } case WM_DESTROY: // Windows is closing down, so we should cleanup ManageEmployeesPaneCleanup( ppszTokenIds, ppcDescriptionString, ulNumTokens ); ppszTokenIds = NULL; ppcDescriptionString = NULL; ulNumTokens = 0; return ( 1 ); case WM_HEARTHEVOICE: // Set the voice to play LoadString( g_hInst, IDS_VOICESPEAK, g_szCounterDisplay, MAX_LOADSTRING ); g_cpVoice->Speak( CT2W(g_szCounterDisplay), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL ); return ( 1 ); case WM_MISCCOMMAND: { // Find out the offset from the first property we're interested in, so we can verify that // it's within range. UINT iSelection = (UINT)(lParam - VID_MalesOnly); if ( 2 >= iSelection ) { // If we have a new listing criteria, we basically shutdown the pane and start it again if ( iSelection != iCurEnum ) { HRESULT hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); hr = g_cpCmdGrammar->SetRuleIdState( VID_OtherRules, SPRS_INACTIVE ); _ASSERTE( SUCCEEDED( hr ) ); ManageEmployeesPaneCleanup( ppszTokenIds, ppcDescriptionString, ulNumTokens ); ppszTokenIds = NULL; ppcDescriptionString = NULL; ulNumTokens = 0; PostMessage( hWnd, WM_INITPANE, 0, (LPARAM) iSelection ); } } return ( 1 ); } case WM_TTSVOICESEL: { // If we are out of range, it is a programming error _ASSERTE( 0 <= lParam && ulNumTokens > (ULONG) lParam ); // The returned Id is an index into our tokenId table, so create a token from the id CComPtr< ISpObjectToken > pToken; HRESULT hr = SpGetTokenFromId( ppszTokenIds[lParam], &pToken, FALSE); if ( SUCCEEDED( hr ) ) { // Set our current voice from the returned token hr = g_cpVoice->SetVoice( pToken ); _ASSERTE( SUCCEEDED( hr ) ); // Change our current voice index ulCurToken = (UINT)lParam; } InvalidateRect( hWnd, NULL, TRUE ); return ( 1 ); } } return ( 0 ); }