251 lines
7.3 KiB
C++
251 lines
7.3 KiB
C++
/****************************************************************************
|
|
*
|
|
* BasicTTS.cpp
|
|
*
|
|
* Sample text-to-speech program that demonstrates the basics of using the
|
|
* SAPI 5.0 TTS APIs.
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation All Rights Reserved.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
//--- Includes --------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <atlbase.h>
|
|
#include <shellapi.h>
|
|
#include <sapi.h>
|
|
|
|
//--- Const Defines----------------------------------------------------------
|
|
|
|
const static WCHAR g_szMarkupDemo[] =
|
|
L"<VOICE OPTIONAL=\"Female\">Tags can be used to change attributes such as\n"
|
|
L" <VOICE OPTIONAL=\"Gender=Male;Volume=Loud\">the voice font that is used,</VOICE>\n"
|
|
L" the <VOLUME LEVEL=\"65\">volume of the voice</VOLUME>\n"
|
|
L" and other attributes of speech such as pitch and rate.\n"
|
|
L"</VOICE>\n\n";
|
|
|
|
|
|
/****************************************************************************
|
|
* MixWithWav *
|
|
*------------*
|
|
* Description:
|
|
* Plays an introductory audio file followed by synthetic speech.
|
|
*
|
|
* Returns:
|
|
* HRESULT from Speak call or
|
|
* S_FALSE if the Intro.Wav file is not present
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT MixWithWav(ISpVoice * pVoice)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
#ifndef _WIN32_WCE
|
|
wprintf(L"Now a sample of mixed wave files and generated speech.\n\n");
|
|
#else
|
|
OutputDebugString(L"Now a sample of mixed wave files and generated speech.\n\n");
|
|
#endif
|
|
hr = pVoice->Speak(L"Intro.Wav", SPF_IS_FILENAME | SPF_ASYNC, NULL);
|
|
if (hr == STG_E_FILENOTFOUND)
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
wprintf(L"ERROR: Can not find file Intro.Wav. Wave file mixing sample will be skipped.\n\n");
|
|
#else
|
|
OutputDebugStringW(L"ERROR: Can not find file Intro.Wav. Wave file mixing sample will be skipped.\n\n");
|
|
#endif
|
|
hr = S_FALSE; // Return success code so sample will continue...
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pVoice->Speak(L"<VOICE OPTIONAL=\"Male\">one hundred eighty dollars and twenty seven cents.</VOICE>", 0, NULL );
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* CreateSampleFile *
|
|
*------------------*
|
|
* Description:
|
|
* Creates a file named Created.Wav using a TTS voice and then starts
|
|
* the currently registered audio playback application.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT CreateSampleFile(ISpVoice * pVoice)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComPtr<ISpStream> cpWavStream;
|
|
WAVEFORMATEX wfex;
|
|
wfex.wFormatTag = WAVE_FORMAT_PCM;
|
|
wfex.nChannels = 1;
|
|
wfex.nSamplesPerSec = 22050;
|
|
wfex.nAvgBytesPerSec = 22050 * 2;
|
|
wfex.nBlockAlign = 2;
|
|
wfex.wBitsPerSample = 16;
|
|
wfex.cbSize = 0;
|
|
hr = cpWavStream.CoCreateInstance(CLSID_SpStream);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = cpWavStream->BindToFile(L"Created.Wav", SPFM_CREATE_ALWAYS, &SPDFID_WaveFormatEx, &wfex, 0);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pVoice->SetOutput(cpWavStream, TRUE);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pVoice->Speak( L"This audio file was created using SAPI five text to speech.", 0, NULL);
|
|
pVoice->SetOutput(NULL, TRUE);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = cpWavStream->Close();
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
printf("Now I'll start the media player on the created file...");
|
|
#else
|
|
OutputDebugString(L"Now I'll start the media player on the created file...");
|
|
#endif
|
|
pVoice->Speak( L"Press the play button to play the recorded audio.", 0, NULL);
|
|
#ifndef _WIN32_WCE
|
|
::ShellExecute(NULL, "open", _T("Created.Wav"), NULL, NULL, SW_SHOWNORMAL);
|
|
#endif
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* SpeakWithEvents *
|
|
*-----------------*
|
|
* Description:
|
|
* Speaks the provided text string and displays the words when the
|
|
* they are spoken.
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
|
|
HRESULT SpeakWithEvents(ISpVoice * pVoice, const WCHAR * psz)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
hr = pVoice->SetInterest(SPFEI(SPEI_WORD_BOUNDARY) | SPFEI(SPEI_END_INPUT_STREAM), 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pVoice->Speak(psz, SPF_ASYNC, NULL);
|
|
}
|
|
ULONG i = 0;
|
|
bool fDone = false;
|
|
while (SUCCEEDED(hr) && (!fDone))
|
|
{
|
|
hr = pVoice->WaitForNotifyEvent(INFINITE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SPVOICESTATUS Stat;
|
|
hr = pVoice->GetStatus(&Stat, NULL);
|
|
if (SUCCEEDED(hr) && (Stat.dwRunningState & SPRS_DONE) == 0)
|
|
{
|
|
while (i < Stat.ulInputWordPos + Stat.ulInputWordLen)
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
putwchar(psz[i++]);
|
|
#else
|
|
WCHAR wsz[2];
|
|
wsz[0] = psz[i++];
|
|
wsz[1] = 0;
|
|
OutputDebugStringW(wsz);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
wprintf(L"%s\n\n", psz + i);
|
|
#else
|
|
RETAILMSG(TRUE,(L"%s\n\n", psz + i));
|
|
#endif
|
|
fDone = true;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* main *
|
|
*------*
|
|
* Description:
|
|
* Entry point for sample program
|
|
*
|
|
* Returns:
|
|
* HRESULT
|
|
*
|
|
*****************************************************************************/
|
|
|
|
int _tmain(int argc, TCHAR* argv[])
|
|
{
|
|
HRESULT hr;
|
|
#ifndef _WIN32_WCE
|
|
wprintf(L"SAPI 5.0 Sample TTS Application\n\n");
|
|
#else
|
|
OutputDebugString(L"SAPI 5.0 Sample TTS Application\n\n");
|
|
#endif
|
|
hr = ::CoInitialize(NULL);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
CComPtr<ISpVoice> cpVoice;
|
|
hr = cpVoice.CoCreateInstance(CLSID_SpVoice);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = cpVoice->Speak(L"This sample program uses basic text to speech operations.", 0, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
wprintf(g_szMarkupDemo);
|
|
#else
|
|
OutputDebugString(g_szMarkupDemo);
|
|
#endif
|
|
hr = cpVoice->Speak(g_szMarkupDemo, 0, NULL);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SpeakWithEvents(cpVoice, L"This is a demonstration of how words can be displayed when they are spoken.");
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = MixWithWav(cpVoice);
|
|
}
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CreateSampleFile(cpVoice);
|
|
}
|
|
cpVoice.Release(); // Must release prior to CoUninitialize or we'll GP Fault
|
|
CoUninitialize();
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
#ifndef _WIN32_WCE
|
|
wprintf(L"Sample program failed with error code 0x%x\n", hr);
|
|
#else
|
|
RETAILMSG(TRUE,(L"Sample program failed with error code 0x%x\n", hr));
|
|
#endif
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|