示例#1
0
yarp::sig::Sound SpeechRecognizerModule::toSound(CComPtr<ISpRecoResult> cpRecoResult)
{
    HRESULT hr = S_OK;
    CComPtr<ISpStreamFormat>      cpStreamFormat = NULL;
    SPPHRASE* pPhrase;
    bool successGetPhrase = SUCCEEDED(cpRecoResult->GetPhrase(&pPhrase));
    hr = cpRecoResult->GetAudio(0, pPhrase->Rule.ulCountOfElements, &cpStreamFormat);

    CComPtr<ISpStream> cpStream;
    ULONG cbWritten = 0; 
   
    string sPath = m_tmpFileFolder + "//tmp.wav";
    //static const WCHAR path[] = L"C://tmpSnd.wav";

    // create file on hard-disk for storing recognized audio, and specify audio format as the retained audio format
    hr = SPBindToFile(s2ws(sPath).c_str(), SPFM_CREATE_ALWAYS, &cpStream, &m_cAudioFmt.FormatId(), m_cAudioFmt.WaveFormatExPtr(), SPFEI_ALL_EVENTS);

    //Continuously transfer data between the two streams until no more data is found (i.e. end of stream)
    //Note only transfer 1000 bytes at a time to creating large chunks of data at one time
    while (TRUE)
    {
        // for logging purposes, the app can retrieve the recognized audio stream length in bytes
        STATSTG stats;
        hr = cpStreamFormat->Stat(&stats, NULL);
        // Check hr

        // create a 1000-byte buffer for transferring
        BYTE bBuffer[1000];
        ULONG cbRead;

        // request 1000 bytes of data from the input stream
        hr = cpStreamFormat->Read(bBuffer, 1000, &cbRead);
        // if data was returned…
        if (SUCCEEDED(hr) && cbRead > 0)
        {
            //then transfer/write the audio to the file-based stream
                hr = cpStream->Write(bBuffer, cbRead, &cbWritten);
            // Check hr
        }

        // since there is no more data being added to the input stream, if the read request returned less than expected, the end of stream was reached, so break data transfer loop
        if (cbRead < 1000)
        {
            break;
        }
    }
    cpStream->Close();
    cpStream.Release();

    yarp::sig::Sound s;
    yarp::sig::file::read(s, sPath.c_str());
    return s;
    return true;
}
/**
	This method uses the sapi helpers to create an ISpStream object
	given an audio file
	@param audioFile - [in] path to audio file
	@return true if successful, false if not. Sets an appropriate error code
**/
bool sapi_lipsync::loadAudio(const std::wstring& audioFile)
{
    HRESULT hr = S_OK;

	this->m_strAudioFile = audioFile;
    try
    {
        m_bDone = false;
		
        hr = SPBindToFile(audioFile.c_str(), SPFM_OPEN_READONLY, &this->m_audioStream);
        if (hr != S_OK)
        {
            m_err = L"Error: Can't open audio file";
            throw(hr);
        }
        GUID guid; // unused
        hr = this->m_audioStream->GetFormat(&guid, &m_pWaveFmt);
        if (hr != S_OK)
        {
            m_err = L"Error: cannot get audio formatting information";
            throw (hr);
        }
        
        /// set the input stream to our newly created audio file
        hr = this->m_recog->SetInput(this->m_audioStream, TRUE);
        if (hr != S_OK)
        {
            m_err = L"Error: cannot set the input stream for ASR";
            throw (hr);
        }
    }
    catch (HRESULT& _hr)
    {
        hr = _hr;
    }
    return (hr == S_OK);

}
void CTTSApp::MainHandleCommand( int id, HWND hWndControl, UINT codeNotify )
/////////////////////////////////////////////////////////////////
//
// Handle each of the WM_COMMAND messages that come in, and deal with
// them appropriately
//
{
    UINT                cNumChar = 0;
    HRESULT             hr = S_OK;
    TCHAR               szAFileName[NORM_SIZE] = _T("");
    static BOOL         bIsUnicode = FALSE;
    BOOL                bWavFileOpened = FALSE;
    LRESULT             iFormat;
    CComPtr<ISpStream>  cpWavStream;
    CComPtr<ISpStreamFormat>    cpOldStream;
    HWND                hwndEdit;
    BOOL                bFileOpened = FALSE;

    // Get handle to the main edit box
    hwndEdit = GetDlgItem( m_hWnd, IDE_EDITBOX );

    switch(id)
    {
        // About Box display
        case IDC_ABOUT:
            ::DialogBox( m_hInst, (LPCTSTR)IDD_ABOUT, m_hWnd, (DLGPROC)About );
            break;

        // Any change to voices is sent to VoiceChange() function
        case IDC_COMBO_VOICES:
            if( codeNotify == CBN_SELCHANGE )
            {
                hr = VoiceChange();
            }

            if( FAILED( hr ) )
            {
                TTSAppStatusMessage( m_hWnd, _T("Error changing voices\r\n") );
            }

            break;

        // If user wants to speak a file pop the standard windows open file
        // dialog box and load the text into a global buffer (m_pszwFileText)
        // which will be used when the user hits speak.
        case IDB_OPEN:
            bFileOpened = CallOpenFileDialog( szAFileName,
                        _T("TXT (*.txt)\0*.txt\0XML (*.xml)\0*.xml\0All Files (*.*)\0*.*\0") );
            if( bFileOpened )
            {
                DWORD   dwFileSize = 0;
                
                wcscpy_s( m_szWFileName, _countof(m_szWFileName), CT2W( szAFileName ) );
                ReadTheFile( szAFileName, &bIsUnicode, &m_pszwFileText );
                
                if( bIsUnicode )
                {
                    // Unicode source
                    UpdateEditCtlW( m_pszwFileText );
                }
                else
                {
                    // MBCS source
#ifdef _UNICODE
                    LPTSTR pszFileText = _tcsdup( m_pszwFileText );
#else
                    // We're compiling ANSI, so we need to convert the string to MBCS
                    // Note that a W2T may not be good here, since this string might 
                    // be very big
                    LPTSTR pszFileText = NULL;
                    int iNeeded = ::WideCharToMultiByte( CP_ACP, 0, m_pszwFileText, -1, NULL, 0, NULL, NULL );
                    pszFileText = (LPTSTR) ::malloc( sizeof( TCHAR ) * ( iNeeded + 1 ) );
                    ::WideCharToMultiByte( CP_ACP, 0, m_pszwFileText, -1, pszFileText, iNeeded + 1, NULL, NULL );
#endif
                    if ( pszFileText )
                    {
                        SetDlgItemText( m_hWnd, IDE_EDITBOX, pszFileText );
                        free( pszFileText );
                    }

                }
            }
            else
            {
                wcscpy_s( m_szWFileName, _countof(m_szWFileName), L"" );
            }
            // Always SetFocus back to main edit window so text highlighting will work
            SetFocus( hwndEdit );
            break;
        
        // Handle speak
        case IDB_SPEAK:
            HandleSpeak();
            break;

        case IDB_PAUSE:
            if( !m_bStop )
            {
                if( !m_bPause )
                {
                    SetWindowText( GetDlgItem( m_hWnd, IDB_PAUSE ), _T("Resume") );
                    // Pause the voice...
                    m_cpVoice->Pause();
                    m_bPause = TRUE;
                    TTSAppStatusMessage( m_hWnd, _T("Pause\r\n") );
                }
                else
                {
                    SetWindowText( GetDlgItem( m_hWnd, IDB_PAUSE ), _T("Pause") );
                    m_cpVoice->Resume();
                    m_bPause = FALSE;
                }
            }
            SetFocus( hwndEdit );
            break;

        case IDB_STOP:
            TTSAppStatusMessage( m_hWnd, _T("Stop\r\n") );
            // Set the global audio state to stop
            Stop();
            SetFocus( hwndEdit );
            break;

        case IDB_SKIP:
            {
                SetFocus( hwndEdit );
                int fSuccess = false;
                int SkipNum = GetDlgItemInt( m_hWnd, IDC_SKIP_EDIT, &fSuccess, true );
                ULONG ulGarbage = 0;
                WCHAR szGarbage[] = L"Sentence";
                if ( fSuccess )
                {
                    TTSAppStatusMessage( m_hWnd, _T("Skip\r\n") );
                    m_cpVoice->Skip( szGarbage, SkipNum, &ulGarbage );
                }
                else
                {
                    TTSAppStatusMessage( m_hWnd, _T("Skip failed\r\n") );
                }
                break;
            }

        case IDE_EDITBOX:
            // Set the global audio state to stop if user has changed contents of edit control
            if( codeNotify == EN_CHANGE )
            {
                Stop();
            }
            break;

        case IDB_SPEAKWAV:
            bWavFileOpened = CallOpenFileDialog( szAFileName,
                         _T("WAV (*.wav)\0*.wav\0All Files (*.*)\0*.*\0") );
            // Speak the wav file using SpeakStream
            if( bWavFileOpened )
            {
                WCHAR                       szwWavFileName[NORM_SIZE] = L"";;

                wcscpy_s( szwWavFileName, _countof(szwWavFileName), CT2W( szAFileName ) );

                // User helper function found in sphelper.h to open the wav file and
                // get back an IStream pointer to pass to SpeakStream
                hr = SPBindToFile( szwWavFileName, SPFM_OPEN_READONLY, &cpWavStream );

                if( SUCCEEDED( hr ) )
                {
                    hr = m_cpVoice->SpeakStream( cpWavStream, SPF_ASYNC, NULL );
                }

                if( FAILED( hr ) )
                {
                    TTSAppStatusMessage( m_hWnd, _T("Speak error\r\n") );
                }
            }
            break;

        // Reset all values to defaults
        case IDB_RESET:
            TTSAppStatusMessage( m_hWnd, _T("Reset\r\n") );
            SendDlgItemMessage( m_hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, m_DefaultVolume );
            SendDlgItemMessage( m_hWnd, IDC_RATE_SLIDER, TBM_SETPOS, TRUE, m_DefaultRate );
            SendDlgItemMessage( m_hWnd, IDC_SAVETOWAV, BM_SETCHECK, BST_UNCHECKED, 0 );
            SendDlgItemMessage( m_hWnd, IDC_EVENTS, BM_SETCHECK, BST_UNCHECKED, 0 );
            SetDlgItemText( m_hWnd, IDE_EDITBOX, _T("Enter text you wish spoken here.") );

            // reset output format
            SendDlgItemMessage( m_hWnd, IDC_COMBO_OUTPUT, CB_SETCURSEL, m_DefaultFormatIndex, 0 );
            SendMessage( m_hWnd, WM_COMMAND, MAKEWPARAM(IDC_COMBO_OUTPUT, CBN_SELCHANGE), 0 );

            // Change the volume and the rate to reflect what the UI says
            HandleScroll( ::GetDlgItem( m_hWnd, IDC_VOLUME_SLIDER ) );
            HandleScroll( ::GetDlgItem( m_hWnd, IDC_RATE_SLIDER ) );

            SetFocus( hwndEdit );
            break;

        case IDC_COMBO_OUTPUT:
            if( codeNotify == CBN_SELCHANGE )
            {
                // Get the audio output format and set it's GUID
                iFormat  = SendDlgItemMessage( m_hWnd, IDC_COMBO_OUTPUT, CB_GETCURSEL, 0, 0 );
                SPSTREAMFORMAT eFmt = (SPSTREAMFORMAT)SendDlgItemMessage( m_hWnd, IDC_COMBO_OUTPUT,
                                                        CB_GETITEMDATA, iFormat, 0 );
                CSpStreamFormat Fmt;
                Fmt.AssignFormat(eFmt);
                if ( m_cpOutAudio )
                {
                    hr = m_cpOutAudio->SetFormat( Fmt.FormatId(), Fmt.WaveFormatExPtr() );
                }
                else
                {
                    hr = E_FAIL;
                }

                if( SUCCEEDED( hr ) )
                {
                    hr = m_cpVoice->SetOutput( m_cpOutAudio, FALSE );
                }

                if( FAILED( hr ) )
                {
                    TTSAppStatusMessage( m_hWnd, _T("Format rejected\r\n") );
                }

                EnableSpeakButtons( SUCCEEDED( hr ) );
            }
            break;

        case IDC_SAVETOWAV:
        {
            TCHAR szFileName[256];
            _tcscpy_s(szFileName, _countof(szFileName), _T("\0"));

            bFileOpened = CallSaveFileDialog( szFileName,
                        _T("WAV (*.wav)\0*.wav\0All Files (*.*)\0*.*\0") );

            if (bFileOpened == FALSE) break;

            wcscpy_s( m_szWFileName, _countof(m_szWFileName), CT2W(szFileName) );

            CSpStreamFormat OriginalFmt;
            hr = m_cpVoice->GetOutputStream( &cpOldStream );
            if (hr == S_OK)
            {
                hr = OriginalFmt.AssignFormat(cpOldStream);
            }
            else
            {
                hr = E_FAIL;
            }
            // User SAPI helper function in sphelper.h to create a wav file
            if (SUCCEEDED(hr))
            {
                hr = SPBindToFile( m_szWFileName, SPFM_CREATE_ALWAYS, &cpWavStream, &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr() ); 
            }
            if( SUCCEEDED( hr ) )
            {
                // Set the voice's output to the wav file instead of the speakers
                hr = m_cpVoice->SetOutput(cpWavStream, TRUE);
            }

            if ( SUCCEEDED( hr ) )
            {
                // Do the Speak
                HandleSpeak();
            }

            // Set output back to original stream
            // Wait until the speak is finished if saving to a wav file so that
            // the smart pointer cpWavStream doesn't get released before its
            // finished writing to the wav.
            m_cpVoice->WaitUntilDone( INFINITE );
            cpWavStream.Release();
            
            // Reset output
            m_cpVoice->SetOutput( cpOldStream, FALSE );
            
            TCHAR   szTitle[MAX_PATH];
            TCHAR   szConfString[MAX_PATH];
            if ( SUCCEEDED( hr ) )
            {
                LoadString( m_hInst, IDS_SAVE_NOTIFY, szConfString, MAX_PATH );
                LoadString( m_hInst, IDS_NOTIFY_TITLE, szTitle, MAX_PATH );
                MessageBox( m_hWnd, szConfString, szTitle, MB_OK | MB_ICONINFORMATION );
            }
            else
            {
                LoadString( m_hInst, IDS_SAVE_ERROR, szConfString, MAX_PATH );
                MessageBox( m_hWnd, szConfString, NULL, MB_ICONEXCLAMATION );
            }

            break;
        }
    }
    
    return;
}
示例#4
0
	void Sound::test() {

		ISpVoice * pVoice = NULL;
		ISpObjectToken*        pVoiceToken=nullptr;
		IEnumSpObjectTokens*   pEnum;
		ULONG                  ulCount = 0;

		if (FAILED(::CoInitialize(NULL)))
		{
			return;
		}
		HRESULT hr = S_OK;

		// Find the best matching installed en-us recognizer.
		CComPtr<ISpObjectToken> cpRecognizerToken;

		if (SUCCEEDED(hr))
		{
			hr = SpFindBestToken(SPCAT_RECOGNIZERS, L"language=409", NULL, &cpRecognizerToken);
		}

		// Create the in-process recognizer and immediately set its state to inactive.
		CComPtr<ISpRecognizer> cpRecognizer;

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecognizer(cpRecognizerToken);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecoState(SPRST_INACTIVE);
		}

		// Create a new recognition context from the recognizer.
		CComPtr<ISpRecoContext> cpContext;

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->CreateRecoContext(&cpContext);
		}

		// Subscribe to the speech recognition event and end stream event.
		if (SUCCEEDED(hr))
		{
			ULONGLONG ullEventInterest = SPFEI(SPEI_RECOGNITION);
			hr = cpContext->SetInterest(ullEventInterest, ullEventInterest);
		}

		// Establish a Win32 event to signal when speech events are available.
		HANDLE hSpeechNotifyEvent = INVALID_HANDLE_VALUE;

		if (SUCCEEDED(hr))
		{
			hr = cpContext->SetNotifyWin32Event();
		}

		if (SUCCEEDED(hr))
		{
			hSpeechNotifyEvent = cpContext->GetNotifyEventHandle();

			if (INVALID_HANDLE_VALUE == hSpeechNotifyEvent)
			{
				// Notification handle unsupported.
				hr = E_NOINTERFACE;
			}
		}

		// Initialize an audio object to use the default audio input of the system and set the recognizer to use it.
		CComPtr<ISpAudio> cpAudioIn;

		if (SUCCEEDED(hr))
		{
			hr = cpAudioIn.CoCreateInstance(CLSID_SpMMAudioIn);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetInput(cpAudioIn, TRUE);
		}

		// Populate a WAVEFORMATEX struct with our desired output audio format. information.
		WAVEFORMATEX* pWfexCoMemRetainedAudioFormat = NULL;
		GUID guidRetainedAudioFormat = GUID_NULL;

		if (SUCCEEDED(hr))
		{
			hr = SpConvertStreamFormatEnum(SPSF_16kHz16BitMono, &guidRetainedAudioFormat, &pWfexCoMemRetainedAudioFormat);
		}

		// Instruct the recognizer to retain the audio from its recognition results.
		if (SUCCEEDED(hr))
		{
			hr = cpContext->SetAudioOptions(SPAO_RETAIN_AUDIO, &guidRetainedAudioFormat, pWfexCoMemRetainedAudioFormat);
		}

		if (NULL != pWfexCoMemRetainedAudioFormat)
		{
			CoTaskMemFree(pWfexCoMemRetainedAudioFormat);
		}

		// Create a new grammar and load an SRGS grammar from file.
		CComPtr<ISpRecoGrammar> cpGrammar;

		if (SUCCEEDED(hr))
		{
			hr = cpContext->CreateGrammar(0, &cpGrammar);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpGrammar->LoadCmdFromFile(L"grammar.grxml", SPLO_STATIC);
		}

		// Set all top-level rules in the new grammar to the active state.
		if (SUCCEEDED(hr))
		{
			hr = cpGrammar->SetRuleState(NULL, NULL, SPRS_ACTIVE);
		}

		// Set the recognizer state to active to begin recognition.
		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecoState(SPRST_ACTIVE_ALWAYS);
		}

		// Establish a separate Win32 event to signal the event loop exit.
		HANDLE hExitEvent = CreateEventW(NULL, FALSE, FALSE, NULL);

		// Collect the events listened for to pump the speech event loop.
		HANDLE rghEvents[] = { hSpeechNotifyEvent, hExitEvent };

		// Speech recognition event loop.
		BOOL fContinue = TRUE;

		while (fContinue && SUCCEEDED(hr))
		{
			// Wait for either a speech event or an exit event, with a 15 second timeout.
			DWORD dwMessage = WaitForMultipleObjects(sp_countof(rghEvents), rghEvents, FALSE, 15000);

			switch (dwMessage)
			{
				// With the WaitForMultipleObjects call above, WAIT_OBJECT_0 is a speech event from hSpeechNotifyEvent.
			case WAIT_OBJECT_0:
			{
				// Sequentially grab the available speech events from the speech event queue.
				CSpEvent spevent;

				while (S_OK == spevent.GetFrom(cpContext))
				{
					switch (spevent.eEventId)
					{
					case SPEI_RECOGNITION:
					{
						// Retrieve the recognition result and output the text of that result.
						ISpRecoResult* pResult = spevent.RecoResult();

						LPWSTR pszCoMemResultText = NULL;
						hr = pResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &pszCoMemResultText, NULL);

						if (SUCCEEDED(hr))
						{
							wprintf(L"Recognition event received, text=\"%s\"\r\n", pszCoMemResultText);
						}

						// Also retrieve the retained audio we requested.
						CComPtr<ISpStreamFormat> cpRetainedAudio;

						if (SUCCEEDED(hr))
						{
							hr = pResult->GetAudio(0, 0, &cpRetainedAudio);
						}

						// To demonstrate, we'll speak the retained audio back using ISpVoice.
						CComPtr<ISpVoice> cpVoice;

						if (SUCCEEDED(hr))
						{
							hr = cpVoice.CoCreateInstance(CLSID_SpVoice);
						}

						if (SUCCEEDED(hr))
						{
							hr = cpVoice->SpeakStream(cpRetainedAudio, SPF_DEFAULT, 0);
						}

						if (NULL != pszCoMemResultText)
						{
							CoTaskMemFree(pszCoMemResultText);
						}

						break;
					}
					}
				}

				break;
			}
			case WAIT_OBJECT_0 + 1:
			case WAIT_TIMEOUT:
			{
				// Exit event or timeout; discontinue the speech loop.
				fContinue = FALSE;
				//break;
			}
			}
		}

	CoUninitialize();

		CComPtr <ISpVoice>		cpVoice;
		CComPtr <ISpStream>		cpStream;
		CSpStreamFormat			cAudioFmt;

		//Create a SAPI Voice
		hr = cpVoice.CoCreateInstance(CLSID_SpVoice);

		//Set the audio format
		if (SUCCEEDED(hr))
		{
			hr = cAudioFmt.AssignFormat(SPSF_22kHz16BitMono);
		}

		//Call SPBindToFile, a SAPI helper method,  to bind the audio stream to the file
		if (SUCCEEDED(hr))
		{

			hr = SPBindToFile(L"c:\\ttstemp.wav", SPFM_CREATE_ALWAYS,
				&cpStream, &cAudioFmt.FormatId(), cAudioFmt.WaveFormatExPtr());
		}

		//set the output to cpStream so that the output audio data will be stored in cpStream
		if (SUCCEEDED(hr))
		{
			hr = cpVoice->SetOutput(cpStream, TRUE);
		}

		//Speak the text "hello world" synchronously
		if (SUCCEEDED(hr))
		{
			hr = cpVoice->Speak(L"Hello World", SPF_DEFAULT, NULL);
		}

		//close the stream
		if (SUCCEEDED(hr))
		{
			hr = cpStream->Close();
		}

		//Release the stream and voice object
		cpStream.Release();
		cpVoice.Release();

		CComPtr<ISpGrammarBuilder>    cpGrammarBuilder;
		SPSTATEHANDLE                 hStateTravel;
		// Create (if rule does not already exist)
		// top-level Rule, defaulting to Active.
		hr = cpGrammarBuilder->GetRule(L"Travel", 0, SPRAF_TopLevel | SPRAF_Active, TRUE, &hStateTravel);

		// Approach 1: List all possible phrases.
		// This is the most intuitive approach, and it does not sacrifice efficiency
		// because the grammar builder will merge shared sub-phrases when possible.
		// There is only one root state, hStateTravel, and the terminal NULL state,
		// and there are six unique transitions between root state and NULL state.

		/* XML Approximation:
		<rule id="Travel">
		<item> fly to Seattle </item>
		<item> fly to New York </item>
		<item> fly to Washington DC </item>
		<item> drive to Seattle </item>
		<item> drive to New York </item>
		<item> drive to Washington DC </item>
		</rule>
		*/

		// Create set of peer phrases, each containing complete phrase.
		// Note: the word delimiter is set as " ", so that the text we
		// attach to the transition can be multiple words (for example,
		// "fly to Seattle" is implicitly "fly" + "to" + "Seattle"):
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"fly to Seattle", L" ", SPWT_LEXICAL, 1, NULL);
		}
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"fly to New York", L" ", SPWT_LEXICAL, 1, NULL);
		}
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"fly to Washington DC", L" ", SPWT_LEXICAL, 1, NULL);
		}
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"drive to Seattle", L" ", SPWT_LEXICAL, 1, NULL);
		}
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"drive to New York", L" ", SPWT_LEXICAL, 1, NULL);
		}
		if (SUCCEEDED(hr))
		{
			hr = cpGrammarBuilder->AddWordTransition(hStateTravel, NULL, L"drive to Washington DC", L" ", SPWT_LEXICAL, 1, NULL);
		}
		// Find the best matching installed en-US recognizer.
		//CComPtr<ISpObjectToken> cpRecognizerToken;

		if (SUCCEEDED(hr))
		{
			hr = SpFindBestToken(SPCAT_RECOGNIZERS, L"language=409", NULL, &cpRecognizerToken);
		}

		// Create the in-process recognizer and immediately set its state to inactive.
		//CComPtr<ISpRecognizer> cpRecognizer;

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecognizer(cpRecognizerToken);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecoState(SPRST_INACTIVE);
		}

		// Create a new recognition context from the recognizer.
		//CComPtr<ISpRecoContext> cpContext;

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->CreateRecoContext(&cpContext);
		}

		// Subscribe to the speech recognition event and end stream event.
		if (SUCCEEDED(hr))
		{
			ULONGLONG ullEventInterest = SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_END_SR_STREAM);
			hr = cpContext->SetInterest(ullEventInterest, ullEventInterest);
		}

		// Establish a Win32 event to signal when speech events are available.
		//HANDLE hSpeechNotifyEvent = INVALID_HANDLE_VALUE;

		if (SUCCEEDED(hr))
		{
			hr = cpContext->SetNotifyWin32Event();
		}

		if (SUCCEEDED(hr))
		{
			hr = cpContext->SetNotifyWin32Event();
		}

		if (SUCCEEDED(hr))
		{
			hSpeechNotifyEvent = cpContext->GetNotifyEventHandle();

			if (INVALID_HANDLE_VALUE == hSpeechNotifyEvent)
			{
				// Notification handle unsupported
				//hr = SPERR_UNITIALIZED;
			}
		}
		// Set up an audio input stream using a .wav file and set the recognizer's input.
		CComPtr<ISpStream> cpInputStream;

		if (SUCCEEDED(hr))
		{
			hr = SPBindToFile(L"Test.wav", SPFM_OPEN_READONLY, &cpInputStream);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetInput(cpInputStream, TRUE);
		}

		// Create a new grammar and load an SRGS grammar from file.
		//CComPtr<ISpRecoGrammar> cpGrammar;

		if (SUCCEEDED(hr))
		{
			hr = cpContext->CreateGrammar(0, &cpGrammar);
		}

		if (SUCCEEDED(hr))
		{
			hr = cpGrammar->LoadCmdFromFile(L"grammar.grxml", SPLO_STATIC);
		}

		// Set all top-level rules in the new grammar to the active state.
		if (SUCCEEDED(hr))
		{
			hr = cpGrammar->SetRuleState(NULL, NULL, SPRS_ACTIVE);
		}

		// Finally, set the recognizer state to active to begin recognition.
		if (SUCCEEDED(hr))
		{
			hr = cpRecognizer->SetRecoState(SPRST_ACTIVE_ALWAYS);
		}

		 hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void     **)&pVoice);
		if (SUCCEEDED(hr)) {
			hr = SpEnumTokens(SPCAT_VOICES, L"Gender=Female", NULL, &pEnum);
			if (SUCCEEDED(hr))
			{
				// Get the number of voices.
				hr = pEnum->GetCount(&ulCount);
			}

			// Obtain a list of available voice tokens, set
			// the voice to the token, and call Speak.
			while (SUCCEEDED(hr) && ulCount--)			{
				if (pVoiceToken != nullptr) {
					pVoiceToken->Release();
				}

				if (SUCCEEDED(hr))
				{
					hr = pEnum->Next(1, &pVoiceToken, NULL);
				}

				if (SUCCEEDED(hr))
				{
					hr = pVoice->SetVoice(pVoiceToken);
				}

				if (SUCCEEDED(hr))
				{
					wchar_t* start = L"<?xml version=\"1.0\" encoding=\"ISO - 8859 - 1\"?><speak version = \"1.0\" xmlns = \"http://www.w3.org/2001/10/synthesis\"	xml:lang = \"en-US\">";
					wchar_t* end = L"</speak>";
					const wchar_t *xml = L"<voice required = \"Gender=Male\"> hi! <prosody pitch=\"fast\"> This is low pitch. </prosody><prosody volume=\"x - loud\"> This is extra loud volume. </prosody>";
					wstring s = start;
					s += xml;
					s += end;
					
					hr = pVoice->Speak(xml, SPF_IS_XML| SPF_ASYNC, 0);
					//hr = pVoice->Speak(L"How are you?", SPF_DEFAULT, NULL);
				}

			}
			/*
			if (SUCCEEDED(hr)) {
				hr = pEnum->Next(1, &pVoiceToken, NULL);
				if (SUCCEEDED(hr)) {
					hr = pVoice->SetVoice(pVoiceToken);
					// Set the output to the default audio device.
					if (SUCCEEDED(hr)) {
						hr = pVoice->SetOutput(NULL, TRUE);
						if (SUCCEEDED(hr)) {
							hr = pVoice->Speak(L"Hello, world!", SPF_DEFAULT, 0);
						}
					}
				}
			}
			*/
			pVoice->Release();
		}
		::CoUninitialize();
	}
示例#5
0
void sapi::run (const char * text, unsigned samplerate, const char * path)
{
	HRESULT hr = E_FAIL;

	ISpStreamFormat_memblock * pSpStreamFormat_memblock = new ISpStreamFormat_memblock;
	mmh::comptr_t<ISpStreamFormat> pSpStreamFormat = pSpStreamFormat_memblock, pCurSpStreamFormat;

#if 0
	CSpStreamFormat	cAudioFmt;
	mmh::comptr_t<ISpStream> cpStream;

	hr = cAudioFmt.AssignFormat(SPSF_16kHz16BitMono);
	_check_hresult(hr);

	hr = SPBindToFile( pfc::stringcvt::string_wide_from_utf8(path),  SPFM_CREATE_ALWAYS, cpStream.get_pp(), &cAudioFmt.FormatId(), cAudioFmt.WaveFormatExPtr());
	_check_hresult(hr);
#endif

	hr = m_SpVoice->GetOutputStream(pCurSpStreamFormat.get_pp());
	_check_hresult(hr);

	GUID fmt; WAVEFORMATEX * wfe = NULL;
	hr = pCurSpStreamFormat->GetFormat(&fmt, &wfe);
	_check_hresult(hr);
	if (wfe == NULL)
		_check_hresult(E_FAIL);
	if (wfe->nChannels > 1)
	{
		wfe->nBlockAlign /= wfe->nChannels;
		wfe->nAvgBytesPerSec/= wfe->nChannels;
		wfe->nChannels = 1;
	}
	hr = pSpStreamFormat_memblock->AssignFormat(wfe);
	if (wfe) CoTaskMemFree(wfe);
	_check_hresult(hr);

#if 0
	hr = m_SpVoice->SetOutput( cpStream, FALSE );
#else
	hr = m_SpVoice->SetOutput( pSpStreamFormat, FALSE );
#endif
	_check_hresult(hr);

	hr = m_SpVoice->Speak( pfc::stringcvt::string_wide_from_utf8(text),  SPF_DEFAULT, NULL );
	_check_hresult(hr);

#if 0
	hr = cpStream->Close();
	return;
#endif

	const WAVEFORMATEX * pwfex = pSpStreamFormat_memblock->WaveFormatExPtr();
	if (pwfex == NULL)
		_check_hresult(E_FAIL);

	{
		static_api_ptr_t<audio_postprocessor> processor;
		dsp::ptr resampler;
		dsp_chunk_list_impl resampler_chunks;
		audio_chunk_impl chunk;
		mem_block_container_impl_t<pfc::alloc_fast_aggressive> chunk2;
		pfc::array_t<t_uint8, pfc::alloc_fast_aggressive> finalOutStream;

		if (!resampler_entry::g_create(resampler, chunk.get_sample_rate(), samplerate, 1.0))
			throw pfc::exception( pfc::string8() << "Could not create resampler (" << chunk.get_sample_rate() << " Hz -> " << samplerate << " Hz)");

		chunk.set_data_fixedpoint(pSpStreamFormat_memblock->get_ptr(), pSpStreamFormat_memblock->get_size(), pwfex->nSamplesPerSec, pwfex->nChannels, pwfex->wBitsPerSample, 1);
		resampler_chunks.add_chunk(&chunk);
		resampler->run(&resampler_chunks, metadb_handle_ptr(), dsp::FLUSH);

		t_riff_header riff;
		riff.id0 = 'R'|'I'<<8|'F'<<16|'F'<<24;
		riff.id1 = 'f'|'m'<<8|'t'<<16|' '<<24;
		riff.type0 = 'W'|'A'<<8|'V'<<16|'E'<<24;
		riff.id2 = 'd'|'a'<<8|'t'<<16|'a'<<24;
		riff.headersize = sizeof(riff.header);

		riff.header.wFormatTag=WAVE_FORMAT_PCM;

		riff.header.nSamplesPerSec = samplerate;//pwfex->nSamplesPerSec;
		riff.header.nChannels = pwfex->nChannels;
		riff.header.wBitsPerSample = pwfex->wBitsPerSample;
		riff.header.nBlockAlign=(riff.header.nChannels*riff.header.wBitsPerSample )/8;
		riff.header.nAvgBytesPerSec =(riff.header.nBlockAlign*riff.header.nSamplesPerSec );

		riff.datasize = (unsigned)chunk.get_sample_count()*riff.header.nBlockAlign;
		riff.filesize = riff.datasize + sizeof(riff);

		abort_callback_impl p_abort;
		file::ptr p_file;
		filesystem::g_open_write_new(p_file, path, p_abort);
		t_size i, count = resampler_chunks.get_count();
		for (i=0; i<count; i++)
		{
			audio_chunk * pChunk = resampler_chunks.get_item(i);
			if (pChunk)
			{
				processor->run(*pChunk, chunk2, 16, 16, false, 1.0);
				finalOutStream.append_fromptr((t_uint8*)chunk2.get_ptr(), chunk2.get_size());
			}
		}
		resampler_chunks.remove_all();
		riff.datasize = (unsigned)finalOutStream.get_size();
		riff.filesize = riff.datasize + sizeof(riff);
		p_file->write(&riff, sizeof(riff), p_abort);
		p_file->write(finalOutStream.get_ptr(), finalOutStream.get_size(), p_abort);
	}

}
//デバッグ用 認識結果をWaveファイルとして保存する
xreturn::r<bool> Recognition_SAPI::DebugSaveWavFile(const std::string& directory,ISpStreamFormat* streamFormat) const
{
	HRESULT hr;
	_USE_WINDOWS_ENCODING;

	const SPSTREAMFORMAT spFormat = SPSF_22kHz8BitMono;
	CSpStreamFormat Fmt( spFormat, &hr);
	if(FAILED(hr))	 return xreturn::windowsError(hr);

	{
		CSpStreamFormat OriginalFmt;
		{
			OriginalFmt.AssignFormat(streamFormat);

			// basic SAPI-stream for file-based storage
			CComPtr<ISpStream> cpStream;
			{
				ULONG cbWritten = 0;

				// create file on hard-disk for storing recognized audio, and specify audio format as the retained audio format
				std::string fff = directory + "\\" + num2str(time(NULL))+".wav";
				hr = SPBindToFile(_A2W(fff.c_str()) , SPFM_CREATE_ALWAYS, &cpStream, &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr(), SPFEI_ALL_EVENTS);
				if(FAILED(hr))	 return xreturn::windowsError(hr);

				// Continuously transfer data between the two streams until no more data is found (i.e. end of stream)
				// Note only transfer 1000 bytes at a time to creating large chunks of data at one time
				while (TRUE)
				{
					// for logging purposes, the app can retrieve the recognized audio stream length in bytes
					STATSTG stats;
					hr = streamFormat->Stat(&stats, NULL);
					if(FAILED(hr))	 return xreturn::windowsError(hr);

					// create a 1000-byte buffer for transferring
					BYTE bBuffer[1000];
					ULONG cbRead;

					// request 1000 bytes of data from the input stream
					hr = streamFormat->Read(bBuffer, 1000, &cbRead);
					// if data was returned??
					if (SUCCEEDED(hr) && cbRead > 0)
					{
						// then transfer/write the audio to the file-based stream
						hr = cpStream->Write(bBuffer, cbRead, &cbWritten);
						if(FAILED(hr))	 return xreturn::windowsError(hr);
					}

					// since there is no more data being added to the input stream, if the read request returned less than expected, the end of stream was reached, so break data transfer loop
					if (cbRead < 1000)
					{
						break;
					}
				}
			}
			// explicitly close the file-based stream to flush file data and allow app to immediately use the file
			hr = cpStream->Close();
			if(FAILED(hr))	 return xreturn::windowsError(hr);
		}
	}
	return true;
}