Esempio n. 1
0
//------------------------------------------------------------------------------
bool SpeechApi51::setVoice(const std::wstring &voice)
{
	m_voice = voice;

	if (!isLoaded())
	{
		return true;
	}

	// get a voice enumerator
	CComPtr<IEnumSpObjectTokens> cpEnum;
	if (FAILED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum)))
	{
		return false;
	}

	// iterate through the list till we find a matching voice
	ISpObjectToken *voice_token;
	while (S_OK == cpEnum->Next(1, &voice_token, NULL))
	{
		CSpDynamicString voice_str;

		if (SUCCEEDED(SpGetDescription(voice_token, &voice_str))
			&& (voice == voice_str.Copy()))
		{
			m_sapi->SetVoice(voice_token);
			return true;
		}
	}

	return false;
}
Esempio n. 2
0
QtSpeech::VoiceNames QtSpeech::voices()
{
    VoiceNames vs;       
    ULONG count = 0;
    CComPtr<IEnumSpObjectTokens> voices;

    CoInitialize(NULL);
    SysCall( SpEnumTokens(SPCAT_VOICES, NULL, NULL, &voices), LogicError);
    SysCall( voices->GetCount(&count), LogicError);

    for(int i=0; i< count; i++) {
        WCHAR * w_id = 0L;
        WCHAR * w_name = 0L;
        CComPtr<ISpObjectToken> voice;
        SysCall( voices->Next( 1, &voice, NULL ), LogicError);
        SysCall( SpGetDescription(voice, &w_name), LogicError);
        SysCall( voice->GetId(&w_id), LogicError);

        QString id = QString::fromWCharArray(w_id);
        QString name = QString::fromWCharArray(w_name);
        VoiceName n = { id, name };
        vs << n;

        voice.Release();
    }
    return vs;
}
Esempio n. 3
0
//------------------------------------------------------------------------------
std::vector<std::wstring> SpeechApi51::getVoices() const
{
	std::vector<std::wstring> ret;
	
	CoInitialize(NULL);

	// get a voice enumerator
	CComPtr<IEnumSpObjectTokens> cpEnum;
	if (S_OK != SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum))
	{
		return ret;
	}

	// iterate through the voices and add them to the string vector
	ISpObjectToken *voice_token;
	while (S_OK == cpEnum->Next(1, &voice_token, NULL))
	{
		CSpDynamicString voice_str;

		if (SUCCEEDED(SpGetDescription(voice_token, &voice_str)))
		{
			ret.push_back(voice_str.Copy());
		}
	}

	return ret;
}
Esempio n. 4
0
std::string CSpeechSynthesizer::GetVoice()
{
	wchar_t* desc = new wchar_t[256];
	SpGetDescription(cpToken, &desc);
	char desctext[256] = { 0 };
	wcstombs(desctext, desc, 256);
	std::string voiceName = std::string(desctext);
	return voiceName;
}
Esempio n. 5
0
//Get available voices in system
std::vector<WCHAR*> TTSLib::GetVoices()
{
	std::vector<WCHAR*> voiceNames;
	voiceNames.resize(m_ispObjectTokens.size());
	WCHAR *description;

	for (size_t i = 0; i < m_ispObjectTokens.size(); ++i)
	{
		SpGetDescription(m_ispObjectTokens[i], &description);
		voiceNames[i]= description;
	}
	
	return voiceNames;
}
Esempio n. 6
0
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;
}
void DumpCategory(LPCWSTR category) {
    // enumerate tokens in each category
    IEnumSpObjectTokens *pEnumSpObjectTokens = nullptr;
    HRESULT hr = SpEnumTokens(category, nullptr, nullptr, &pEnumSpObjectTokens);
    if (SPERR_NOT_FOUND == hr) {
        LOG(L"  None found.");
        return;
    } else if (FAILED(hr)) {
        ERR(L"SpEnumTokens failed: hr = 0x%08x", hr);
        return;
    }
    ReleaseOnExit rEnumSpObjectTokens(pEnumSpObjectTokens);
    
    ULONG nTokens = 0;
    hr = pEnumSpObjectTokens->GetCount(&nTokens);
    if (FAILED(hr)) {
        ERR(L"IEnumSpObjectTokens::GetCount failed: hr = 0x%08x", hr);
        return;
    }
    
    for (ULONG token = 0; token < nTokens; token++) {
        ISpObjectToken *pSpObjectToken = nullptr;
        hr = pEnumSpObjectTokens->Next(1, &pSpObjectToken, nullptr);
        if (FAILED(hr)) {
            ERR(L"IEnumSpObjectTokens::Next failed: hr = 0x%08x", hr);
            return;
        }
        ReleaseOnExit rSpObjectToken(pSpObjectToken);
        
        LPWSTR description = nullptr;
        hr = SpGetDescription(pSpObjectToken, &description);
        if (FAILED(hr)) {
            ERR(L"SpGetDescription failed: hr = 0x%08x", hr);
            continue;
        }
        CoTaskMemFreeOnExit fDescription(description);
        
        LOG(L"  #%u: %s", token + 1, description);
 
        EnumDataKey(2, pSpObjectToken);
    }
}
Esempio n. 8
0
QtSpeech::QtSpeech(VoiceName n, QObject * parent)
    :QObject(parent), d(new Private)
{
    ULONG count = 0;
    CComPtr<IEnumSpObjectTokens> voices;

    CoInitialize(NULL);
    SysCall( d->voice.CoCreateInstance( CLSID_SpVoice ), InitError);

    if (n.id.isEmpty()) {
        WCHAR * w_id = 0L;
        WCHAR * w_name = 0L;
        CComPtr<ISpObjectToken> voice;
        SysCall( d->voice->GetVoice(&voice), InitError);
        SysCall( SpGetDescription(voice, &w_name), InitError);
        SysCall( voice->GetId(&w_id), InitError);
        n.name = QString::fromWCharArray(w_name);
        n.id = QString::fromWCharArray(w_id);
        voice.Release();
    }
    else {
        SysCall( SpEnumTokens(SPCAT_VOICES, NULL, NULL, &voices), InitError);
        SysCall( voices->GetCount(&count), InitError);
        for (int i =0; i< count; i++) {
            WCHAR * w_id = 0L;
            CComPtr<ISpObjectToken> voice;
            SysCall( voices->Next( 1, &voice, NULL ), InitError);
            SysCall( voice->GetId(&w_id), InitError);
            QString id = QString::fromWCharArray(w_id);
            if (id == n.id) d->voice->SetVoice(voice);
            voice.Release();
        }
    }

    if (n.id.isEmpty())
        throw InitError(Where+"No default voice in system");

    d->name = n;
    d->ptrs << this;
}
TTSWidget::TTSWidget(QWidget* parent /*= 0*/, Qt::WFlags flags /*= 0*/) : QWidget(parent, flags)
{
	setupUi(this);

#ifdef _WIN32
	CoInitialize(NULL);
	HRESULT                             hr = S_OK;
	CComPtr<ISpObjectToken>             cpVoiceToken;
	CComPtr<IEnumSpObjectTokens>        cpEnum;
	CComPtr<ISpVoice>                   cpVoice;
	ULONG                               ulCount = 0;
	
	// Create the SAPI voice
	if(SUCCEEDED(hr))
		hr = cpVoice.CoCreateInstance( CLSID_SpVoice ); 
	//Enumerate the available voices 
	if(SUCCEEDED(hr))
		hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);
	//Get the number of voices
	if(SUCCEEDED(hr))
		hr = cpEnum->GetCount(&ulCount);
	// Obtain a list of available voice tokens
	while (SUCCEEDED(hr) && ulCount-- )
	{
		cpVoiceToken.Release();
		if(SUCCEEDED(hr))
			hr = cpEnum->Next( 1, &cpVoiceToken, NULL );
		WCHAR* voiceName = 0;
		if (SUCCEEDED(SpGetDescription(cpVoiceToken, &voiceName)))
		{
			m_voice->addItem(QString::fromUtf16((const ushort*) voiceName));
			CoTaskMemFree(voiceName);
		}
	}
	CoUninitialize();
#endif

	connect(m_voice, SIGNAL(currentIndexChanged(int)), this, SLOT(voiceChanged(int)));
	connect(m_speakButton, SIGNAL(clicked()), this, SLOT(speak()));	
}
Esempio n. 10
0
bool SapiInterface::SetVoiceNative(CString voice)
{
	CComPtr<IEnumSpObjectTokens>    cpEnum;
	CSpDynamicString*				szDescription;
	CComPtr<ISpObjectToken>         cpVoiceToken; //the token is the voice
	CComPtr<ISpVoice>               cpVoice;
	ULONG                           ulCount = 0;

	//This gets an enumeration of all voices on the system
	hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);
	if (!SUCCEEDED(hr) ){
		return false; //enumeration of voices failed
	}

	hr = cpEnum->GetCount(&ulCount);
	szDescription = new CSpDynamicString [ulCount];
	UINT i = 0;
	while (SUCCEEDED(hr) && ulCount--)
	{
	   cpVoiceToken.Release();
	   if (SUCCEEDED (hr))
	   {
		  hr = cpEnum->Next(1, &cpVoiceToken, NULL);
		  hr = SpGetDescription(cpVoiceToken, &szDescription[i]);
	   }
	   if (SUCCEEDED (hr))
	   {
		  if(CString(szDescription[i]) == voice) {
				hr = pVoice->SetVoice(cpVoiceToken);
				delete [] szDescription;
				return true;
		   }
	   }
		i++;
	}
	//delete the voice list if one is not found and return false
	delete [] szDescription;
	return false;
}
Esempio n. 11
0
// implementation
QtSpeech::QtSpeech(QObject * parent)
    :QObject(parent), d(new Private)
{
    CoInitialize(NULL);
    SysCall( d->voice.CoCreateInstance( CLSID_SpVoice ), InitError);

    VoiceName n;
    WCHAR * w_id = 0L;
    WCHAR * w_name = 0L;
    CComPtr<ISpObjectToken> voice;
    SysCall( d->voice->GetVoice(&voice), InitError);
    SysCall( SpGetDescription(voice, &w_name), InitError);
    SysCall( voice->GetId(&w_id), InitError);
    n.name = QString::fromWCharArray(w_name);
    n.id = QString::fromWCharArray(w_id);
    voice.Release();

    if (n.id.isEmpty())
        throw InitError(Where+"No default voice in system");

    d->name = n;
    d->ptrs << this;
}
Esempio n. 12
0
int voice_getVoices(lua_State *L)
{
    if (!pVoice || !pTokens)
        return error_voice(L);
    if (lua_gettop(L) == 0) 
    {
        ULONG count = 0;
        HRESULT hr = pTokens->GetCount(&count);
        if (FAILED(hr))
        {
            lua_pushnil(L);
            return 1;    
        }
        lua_newtable(L);
        WCHAR *buffer = NULL;
        ISpObjectToken *token = NULL;
        for (ULONG i=0; i<count; ++i)
        {
            pTokens->Item(i, &token);
            LANGID lang = 0;
            hr = SpGetLanguageFromToken(token, &lang);
            if (SUCCEEDED(hr))
                hr = SpGetDescription(token, &buffer, lang);
            token->Release();
            token=NULL;
            if (SUCCEEDED(hr)) {
            lua_pushinteger(L, i+1);
            lua_pushwstring(L, buffer);
            lua_settable(L, -3);        
            CoTaskMemFree(buffer);
            buffer = NULL;
            } 
        }
        return 1;
    }
    return error_invargs(L, L"getVoices");
}
Esempio n. 13
0
/*
 * Some notes about this function:
 * This function returns a list of available SAPI voices. It has been fixed and should be working correclty
 * on Windows 7 and all other versions of Windows.
 *
 * The solution to getting this function working was found here:
 * http://stackoverflow.com/questions/4336245/how-to-return-a-java-string-in-c-using-jni
 *
 * In addition to the above StackOverflow thread, it was necessary to change this function to return an std::string instance instead
 * of a character pointer, and to use stringstreams instead of CStrings.
 */
std::string SapiInterface::GetVoiceNative()
{
	
	std::stringstream sstream;
	sstream << "<?xml version=\"1.0\"?>";

	ISpVoice * pVoice = NULL;	
	CComPtr<ISpObjectToken>        cpVoiceToken;
	CComPtr<IEnumSpObjectTokens>   cpEnum;
	CComPtr<ISpVoice>              cpVoice;
	ULONG                          ulCount = 0;

	HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
	if(SUCCEEDED(hr))
	{
		WCHAR   **m_ppszTokenIds;
		USES_CONVERSION;
		CComPtr<IEnumSpObjectTokens>    cpEnum;
		WCHAR**							szDescription;
		ISpObjectToken                  *pToken = NULL;
		CComPtr<ISpObjectToken>         cpVoiceToken; //the token is the voice
		CComPtr<ISpVoice>               cpVoice;
		ULONG                           ulCount = 0;

		if(SUCCEEDED(hr))
		{
			hr = cpVoice.CoCreateInstance( CLSID_SpVoice );
			if(SUCCEEDED(hr))
			{
				WCHAR *pszCurTokenId = NULL;
				ULONG ulIndex = 0, ulNumTokens = 0, ulCurToken = -1;

				hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);

				if (hr == S_OK)
				{
					hr = cpEnum->GetCount( &ulNumTokens );

					if (SUCCEEDED(hr) && ulNumTokens != 0)
					{
						szDescription = new WCHAR* [ulNumTokens];
						m_ppszTokenIds = new WCHAR* [ulNumTokens];

						ZeroMemory(m_ppszTokenIds, ulNumTokens * sizeof(WCHAR *));

						UINT i =0;
						while (cpEnum->Next(1, &pToken, NULL) == S_OK)
						{
							//Don't care about return value in next line:
							hr = SpGetDescription(pToken, &szDescription[ulIndex]);
							ulIndex++;

							int utf8_length = WideCharToMultiByte(
								  CP_UTF8,           // Convert to UTF-8
								  0,                 // No special character conversions required 
													 // (UTF-16 and UTF-8 support the same characters)
								  szDescription[i],             // UTF-16 string to convert
								  -1,                // utf16 is NULL terminated (if not, use length)
								  NULL,              // Determining correct output buffer size
								  0,                 // Determining correct output buffer size
								  NULL,              // Must be NULL for CP_UTF8
								  NULL);             // Must be NULL for CP_UTF8

							if (utf8_length == 0) {
								return std::string("WideCharToMultibyte error.");
							}
							
							char *utf8_voice = new char[utf8_length];
							utf8_length = WideCharToMultiByte(
							  CP_UTF8,           // Convert to UTF-8
							  0,                 // No special character conversions required 
												 // (UTF-16 and UTF-8 support the same characters)
							  szDescription[i],             // UTF-16 string to convert
							  -1,                // utf16 is NULL terminated (if not, use length)
							  utf8_voice,              // UTF-8 output buffer
							  utf8_length,       // UTF-8 output buffer size
							  NULL,              // Must be NULL for CP_UTF8
							  NULL);             // Must be NULL for CP_UTF8
							//strConcatenateXML += "<voice>" + szDescription[i] + "</voice>";

							sstream << "<voice>" << utf8_voice << "</voice>";
							pToken->Release();
							pToken = NULL;
							i++;
						}

						delete [] szDescription;
					}
					else
						{
						//strConcatenateXML = "No voice found. (5)";
						sstream << "No voice found. (5)";
					}
				}
				else
				{
					//strConcatenateXML = "No voice found. (4)";
					sstream << "No voice found. (4)";
				}
			}
			else
			{
				//strConcatenateXML = "No voice found. (3)";
				sstream << "No voice found. (3)";
			}
		}
		else
		{
			//strConcatenateXML = "No voice found. (2)";
			sstream << "No voice found. (2)";
		}
	}
	else
	{
		//strConcatenateXML = "No voice found. (1)";
		sstream << "No voice found. (1)";
	}

	return sstream.str();
}
Esempio n. 14
0
/******************************************************************************
* ManageEmployeesPaneProc *
*-------------------------*
*   Description:
*       Handles messages specifically for the manage employees pane.
*
******************************************************************************/
LRESULT ManageEmployeesPaneProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    USES_CONVERSION;
    
    static ULONG ulNumTokens;
    static ULONG ulCurToken;
    static WCHAR**  ppszTokenIds;
    static CSpDynamicString*  ppcDesciptionString;     // This is string helper class in sphelper.h
    
    switch ( message )
    {
        case WM_GOTOOFFICE:
        {
            // Set the right message handler and repaint
            g_fpCurrentPane = OfficePaneProc;
            //Cleanup our variables
            ManageEmployeesPaneCleanup( ppszTokenIds, ppcDesciptionString, ulNumTokens );            
            ppszTokenIds = NULL;
            ppcDesciptionString = NULL;
            ulNumTokens = 0;

            // Set the hear voice rule to inactive
            HRESULT hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_INACTIVE );            
            _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, ppcDesciptionString, ulNumTokens );            
            ppszTokenIds = NULL;
            ppcDesciptionString = NULL;
            ulNumTokens = 0;

            // Set the hear voice rule to inactive
            HRESULT hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_INACTIVE );            
            _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, ppcDesciptionString, ulCurToken );
            return ( 1 );
        }

        case WM_INITPANE:
        {
            ISpObjectToken                  *pToken = NULL;  // Token interface pointer
            CComPtr<IEnumSpObjectTokens>    cpEnum;          // Pointer to token enumerator
            ULONG                           ulIndex = 0;
            ulCurToken = 0xffffffff;

            // Get a token enumerator for tts voices available
            HRESULT hr = SpEnumTokens(SPCAT_VOICES, NULL, 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
                    ppcDesciptionString = new CSpDynamicString [ulNumTokens];
                    if ( NULL == ppcDesciptionString )
                    {
                        hr = E_OUTOFMEMORY;
                        break;
                    }

                    ppszTokenIds = new WCHAR* [ulNumTokens];
                    if ( NULL == ppszTokenIds )
                    {
                        hr = E_OUTOFMEMORY;
                        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, &ppcDesciptionString[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, ppcDesciptionString, ulNumTokens );

                    ppszTokenIds = NULL;
                    ppcDesciptionString = 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
                    HRESULT hr = g_cpVoice->GetVoice( &pToken );
                    if ( SUCCEEDED( hr ) )
                    {
                        // Get the current token ID, and compare it against others to figure out
                        // which desciption 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();

                    }                                       

                }
            
            }

            // Set the hear voice rule to active
            hr = g_cpCmdGrammar->SetRuleIdState( VID_HearTheVoice, SPRS_ACTIVE );            
            _ASSERTE( SUCCEEDED( hr ) );

            return ( 1 );
        }

        case WM_DESTROY:
            // Windows is closing down, so we should cleanup
            ManageEmployeesPaneCleanup( ppszTokenIds, ppcDesciptionString, ulNumTokens );
            return ( 1 );

        case WM_HEARTHEVOICE:
            // Set the voice to play
            LoadString( g_hInst, IDS_VOICESPEAK, g_szCounterDisplay, MAX_LOADSTRING );
            g_cpVoice->Speak( T2W(g_szCounterDisplay), SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL );
    }
    return ( 0 );
}
static void configure()
{
	configure_changed = false;
	GtkWidget *window = gtk_dialog_new_with_buttons(_("SAPI TTS configuration"), GTK_WINDOW(plugin_info->pluginwin), GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
	GtkWidget *vbox = gtk_vbox_new(false, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox),5);
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(window)->vbox), vbox);
	GtkWidget *frame = gtk_frame_new(_("TTS voice engine"));
	gtk_box_pack_start(GTK_BOX(vbox), frame, false, false, 3);
	GtkWidget *table = gtk_table_new(2, 3, false);
	gtk_container_set_border_width(GTK_CONTAINER(table),8);
	gtk_container_add (GTK_CONTAINER (frame), table);
	GtkWidget *label = gtk_label_new(_("Voice :"));
	gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, (GtkAttachOptions)0, 5, 0);
	GtkWidget *combobox = gtk_combo_box_new_text();
	gtk_table_attach(GTK_TABLE(table), combobox, 1, 2, 0, 1, GtkAttachOptions(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 5, 0);

	ULONG ulNumTokens;
	WCHAR** ppszTokenIds = NULL;
	CComPtr<IEnumSpObjectTokens> cpEnum;
	HRESULT hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);
	if ( S_OK == hr ) {
		hr = cpEnum->GetCount( &ulNumTokens );
		if ( SUCCEEDED( hr ) && 0 != ulNumTokens ) {
			WCHAR *pszCurTokenId = NULL;
			ISpObjectToken *pToken;
			HRESULT hr = pVoice->GetVoice( &pToken );
			if ( SUCCEEDED( hr ) ) {
				pToken->GetId( &pszCurTokenId );
				pToken->Release();
			}
			if (pszCurTokenId) {
				ppszTokenIds = new WCHAR* [ulNumTokens];
				ZeroMemory( ppszTokenIds, ulNumTokens*sizeof( WCHAR* ) );
				LONG ulCurToken = -1;
				ULONG ulIndex = 0;
				while (cpEnum->Next(1, &pToken, NULL) == S_OK) {
					WCHAR *description;
					SpGetDescription( pToken, &description);
					DWORD dwNum = WideCharToMultiByte(CP_UTF8,NULL,description,-1,NULL,0,NULL,FALSE);
					char *text = new char[dwNum];
					WideCharToMultiByte (CP_UTF8,NULL,description,-1,text,dwNum,NULL,FALSE);
					gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), text);
					delete []text;
					CoTaskMemFree(description);
					pToken->GetId( &ppszTokenIds[ulIndex]);
					if (ulCurToken == -1 && _wcsicmp( pszCurTokenId, ppszTokenIds[ulIndex]) == 0) {
						ulCurToken = ulIndex;
					}
					ulIndex++;
					pToken->Release();
				}
				CoTaskMemFree( pszCurTokenId );
				if (ulCurToken != -1)
					gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), ulCurToken);
			}
		}
	}
	g_signal_connect (G_OBJECT (combobox), "changed", G_CALLBACK (on_voice_combobox_changed), ppszTokenIds);

	label = gtk_label_new(_("Volume :"));
	gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, (GtkAttachOptions)0, 5, 0);
	GtkWidget *volume_hscale = gtk_hscale_new_with_range(0, 100, 1);
	gtk_table_attach(GTK_TABLE(table), volume_hscale, 1, 2, 1, 2, GtkAttachOptions(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 5, 0);
	USHORT volume;
	pVoice->GetVolume(&volume);
	gtk_range_set_value(GTK_RANGE(volume_hscale), volume);
	g_signal_connect(G_OBJECT(volume_hscale),"value-changed", G_CALLBACK(on_volume_hscale_value_changed), NULL);
	label = gtk_label_new(_("Rate :"));
	gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, (GtkAttachOptions)0, 5, 0);
	GtkWidget *rate_hscale = gtk_hscale_new_with_range(-10, 10, 1);
	gtk_table_attach(GTK_TABLE(table), rate_hscale, 1, 2, 2, 3, GtkAttachOptions(GTK_FILL | GTK_EXPAND), (GtkAttachOptions)0, 5, 0);
	long rate;
	pVoice->GetRate(&rate);
	gtk_range_set_value(GTK_RANGE(rate_hscale), rate);
	g_signal_connect(G_OBJECT(rate_hscale),"value-changed", G_CALLBACK(on_rate_hscale_value_changed), NULL);

	GtkWidget *vbox1 = gtk_vbox_new(false, 5);
	gtk_box_pack_start(GTK_BOX(vbox), vbox1, false, false, 10);
	label = gtk_label_new(_("Input the test text:"));
	gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
	gtk_box_pack_start(GTK_BOX(vbox1), label, false, false, 0);
	GtkWidget *hbox = gtk_hbox_new(false, 5);
	gtk_box_pack_start(GTK_BOX(vbox1), hbox, false, false, 0);
	GtkWidget *entry = gtk_entry_new();
	gtk_entry_set_text(GTK_ENTRY(entry), "This is the test text");
	gtk_box_pack_start(GTK_BOX(hbox), entry, true, true, 0);
	GtkWidget *button = gtk_button_new_with_label(_("Test"));
	gtk_box_pack_start(GTK_BOX(hbox), button, false, false, 0);
	g_signal_connect(G_OBJECT(button),"clicked", G_CALLBACK(on_test_tts_button_clicked), GTK_ENTRY(entry));

	gtk_widget_show_all(vbox);
	gtk_dialog_run(GTK_DIALOG(window));
	if (configure_changed) {
		char *voice = NULL;
		ISpObjectToken *pToken;
		HRESULT hr = pVoice->GetVoice( &pToken );
		if ( SUCCEEDED( hr ) ) {
			WCHAR *id;
			pToken->GetId( &id );
			DWORD dwNum = WideCharToMultiByte(CP_UTF8,NULL,id,-1,NULL,0,NULL,FALSE);
			voice = new char[dwNum];
			WideCharToMultiByte (CP_UTF8,NULL,id,-1,voice,dwNum,NULL,FALSE);
			CoTaskMemFree(id);
			pToken->Release();
		}
		if (voice) {
			gint volume = (gint)gtk_range_get_value(GTK_RANGE(volume_hscale));
			gint rate = (gint)gtk_range_get_value(GTK_RANGE(rate_hscale));
			gchar *data = g_strdup_printf("[sapi_tts]\nvoice=%s\nvolume=%d\nrate=%d\n", voice, volume, rate);
			std::string res = get_cfg_filename();
			g_file_set_contents(res.c_str(), data, -1, NULL);
			g_free(data);
			delete []voice;
		}
	}
	ULONG ulIndex;
	if ( ppszTokenIds ) {
		for ( ulIndex = 0; ulIndex < ulNumTokens; ulIndex++ ) {
			if ( NULL != ppszTokenIds[ulIndex] ) {
				CoTaskMemFree( ppszTokenIds[ulIndex] );
			}
		}
		delete [] ppszTokenIds;
	}
	gtk_widget_destroy (window);
}
/******************************************************************************
* 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 );
}