As its my birthday on the 30th, I've decided to release the source code of my Speech module.
As pointed out by IanM, you'll need Visual C V6 or better to at least try and do anything with it.
// Speech.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include "Speech.h"
#include "sapi.h"
#include "sphelper.h"
/*
This source file is (C) Nicholas Kingsley 2002-2003.
All rights reserved. Whilst the source code is FREEWARE, I retain the copyright on the code.
Please inform me of any bug-fixes, speed improvements etc
Send any comments to : nickk@nildram.co.uk
*/
#include "SPUIHelp.h"
#include
extern CComModule _Module;
#include
#include "E:\Users\Nicholas\Visual Studio Projects\Memory\Memory.h"
#include "Voices.h"
#define SPEECH_EXPORTS
#include "speech.hpp"
ISpVoice *pVoice = NULL;
CComPtr cpEnum=NULL;
CComPtr cpVoiceToken=NULL;
CComPtr cpStream=NULL;
CSpStreamFormat cAudioFmt;
CVoices voices;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CSpeechApp
BEGIN_MESSAGE_MAP(CSpeechApp, CWinApp)
//{{AFX_MSG_MAP(CSpeechApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSpeechApp construction
CSpeechApp::CSpeechApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CSpeechApp object
CSpeechApp theApp;
DWORD DeInitSpeech(void)
{
if (pVoice)
{
pVoice->Release();
pVoice = NULL;
}
if (cpEnum)
{
cpEnum.Release();
cpEnum=NULL;
}
if (cpStream)
{
cpStream.Release();
cpStream=NULL;
}
if (cpVoiceToken)
{
cpVoiceToken.Release();
cpVoiceToken=NULL;
}
CoUninitialize();
voices.DestroyWindow();
return (true);
}
DWORD InitSpeech(void)
{
if (pVoice==NULL)
{
if (FAILED(CoInitialize(NULL)))
{
return (false);
}
if (FAILED(CoCreateInstance(CLSID_SpVoice,
NULL,
CLSCTX_ALL,
IID_ISpVoice,
(void **)&pVoice)))
{
DeInitSpeech();
return (false);
}
if (FAILED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum)))
{
DeInitSpeech();
return (false);
}
// Set the default output
if (FAILED(pVoice->SetOutput(NULL,false)))
{
DeInitSpeech();
return (false);
}
// Get the list of voices
voices.Create(IDD_VOICES);
voices.m_voiceList.ResetContent();
// The easy way of getting voice names...
if (FAILED(SpInitTokenComboBox(GetDlgItem(voices.m_hWnd, IDC_VOICELIST), SPCAT_VOICES)))
{
DeInitSpeech();
return (false);
}
return (true);
}
return (false);
}
DWORD say(LPSTR text,int flags)
{
if (pVoice && text)
{
LPWSTR lpszW=_ASCIIToWide(text);
if (lpszW)
{
pVoice->Speak(lpszW,flags ,NULL);
free(lpszW);
}
}
return (false);
}
DWORD waitUntilDone(long delay)
{
if (pVoice)
{
return (SUCCEEDED(pVoice->WaitUntilDone(delay)) ? true : false);
}
return (false);
}
DWORD setRate(long rate)
{
if (pVoice)
{
return (SUCCEEDED(pVoice->SetRate(rate)) ? true : false);
}
return (false);
}
DWORD getRate(DWORD mem)
{
register long rate;
if (pVoice && mem)
{
if (SUCCEEDED(pVoice->GetRate(&rate)))
{
memcpy((LPSTR) mem,(char *) &rate,sizeof(rate));
return (true);
}
}
return (false);
}
DWORD setVolume(int volume)
{
if (pVoice)
{
return (SUCCEEDED(pVoice->SetVolume(volume)) ? true : false);
}
return (false);
}
DWORD getVolume(DWORD mem)
{
register unsigned short value;
if (pVoice && mem)
{
if (SUCCEEDED(pVoice->GetVolume(&value)))
{
memcpy((LPSTR) mem,(char *) &value,sizeof(value));
return (true);
}
}
return (false);
}
DWORD getNumberOfVoices(DWORD mem)
{
register unsigned long count;
if (pVoice && mem)
{
if (SUCCEEDED(cpEnum->GetCount(&count)))
{
memcpy((LPSTR) mem,(char *) &count,sizeof(count));
return (true);
}
}
return (false);
}
DWORD textToWAV(LPSTR text,LPSTR fileName,int format)
{
register LPWSTR lpszW;
register LPWSTR lpszF;
register bool result;
if (text==NULL || fileName==NULL)
{
return (false);
}
if (FAILED(cAudioFmt.AssignFormat(format==SPSF_Default ? SPSF_Default : \
format==SPSF_NoAssignedFormat ? SPSF_NoAssignedFormat : \
format==SPSF_Text ? SPSF_Text : \
format==SPSF_NonStandardFormat ? SPSF_NonStandardFormat : \
format==SPSF_ExtendedAudioFormat ? SPSF_ExtendedAudioFormat: \
// Standard PCM wave formats
format==SPSF_8kHz8BitMono ? SPSF_8kHz8BitMono : \
format==SPSF_8kHz8BitStereo ? SPSF_8kHz8BitStereo : \
format==SPSF_8kHz16BitMono ? SPSF_8kHz16BitMono : \
format==SPSF_8kHz16BitStereo ? SPSF_8kHz16BitStereo : \
format==SPSF_11kHz8BitMono ? SPSF_11kHz8BitMono : \
format==SPSF_11kHz8BitStereo ? SPSF_11kHz8BitStereo : \
format==SPSF_11kHz16BitMono ? SPSF_11kHz16BitMono : \
format==SPSF_11kHz16BitStereo ? SPSF_11kHz16BitStereo : \
format==SPSF_12kHz8BitMono ? SPSF_12kHz8BitMono : \
format==SPSF_12kHz8BitStereo ? SPSF_12kHz8BitStereo : \
format==SPSF_12kHz16BitMono ? SPSF_12kHz16BitMono : \
format==SPSF_12kHz16BitStereo ? SPSF_12kHz16BitStereo: \
format==SPSF_16kHz8BitMono ? SPSF_16kHz8BitMono : \
format==SPSF_16kHz8BitStereo ? SPSF_16kHz8BitStereo : \
format==SPSF_16kHz16BitMono ? SPSF_16kHz16BitMono : \
format==SPSF_16kHz16BitStereo ? SPSF_16kHz16BitStereo : \
format==SPSF_22kHz8BitMono ? SPSF_22kHz8BitMono : \
format==SPSF_22kHz8BitStereo ? SPSF_22kHz8BitStereo : \
format==SPSF_22kHz16BitMono ? SPSF_22kHz16BitMono : \
format==SPSF_22kHz16BitStereo ? SPSF_22kHz16BitStereo : \
format==SPSF_24kHz8BitMono ? SPSF_24kHz8BitMono : \
format==SPSF_24kHz8BitStereo ? SPSF_24kHz8BitStereo : \
format==SPSF_24kHz16BitMono ? SPSF_24kHz16BitMono : \
format==SPSF_24kHz16BitStereo ? SPSF_24kHz16BitStereo : \
format==SPSF_32kHz8BitMono ? SPSF_32kHz8BitMono : \
format==SPSF_32kHz8BitStereo ? SPSF_32kHz8BitStereo : \
format==SPSF_32kHz16BitMono ? SPSF_32kHz16BitMono : \
format==SPSF_32kHz16BitStereo ? SPSF_32kHz16BitStereo : \
format==SPSF_44kHz8BitMono ? SPSF_44kHz8BitMono : \
format==SPSF_44kHz8BitStereo ? SPSF_44kHz8BitStereo : \
format==SPSF_44kHz16BitMono ? SPSF_44kHz16BitMono : \
format==SPSF_44kHz16BitStereo ? SPSF_44kHz16BitStereo : \
format==SPSF_48kHz8BitMono ? SPSF_48kHz8BitMono : \
format==SPSF_48kHz8BitStereo ? SPSF_48kHz8BitStereo : \
format==SPSF_48kHz16BitMono ? SPSF_48kHz16BitMono : \
format==SPSF_48kHz16BitStereo ? SPSF_48kHz16BitStereo : \
// TrueSpeech format
format==SPSF_TrueSpeech_8kHz1BitMono ? SPSF_TrueSpeech_8kHz1BitMono : \
// A-Law formats
format==SPSF_CCITT_ALaw_8kHzMono ? SPSF_CCITT_ALaw_8kHzMono : \
format==SPSF_CCITT_ALaw_8kHzStereo ? SPSF_CCITT_ALaw_8kHzStereo : \
format==SPSF_CCITT_ALaw_11kHzMono ? SPSF_CCITT_ALaw_11kHzMono : \
format==SPSF_CCITT_ALaw_11kHzStereo ? SPSF_CCITT_ALaw_11kHzStereo : \
format==SPSF_CCITT_ALaw_22kHzMono ? SPSF_CCITT_ALaw_22kHzMono : \
format==SPSF_CCITT_ALaw_22kHzStereo ? SPSF_CCITT_ALaw_22kHzStereo : \
format==SPSF_CCITT_ALaw_44kHzMono ? SPSF_CCITT_ALaw_44kHzMono : \
format==SPSF_CCITT_ALaw_44kHzStereo ? SPSF_CCITT_ALaw_44kHzStereo : \
// u-Law formats
format==SPSF_CCITT_uLaw_8kHzMono ? SPSF_CCITT_uLaw_8kHzMono : \
format==SPSF_CCITT_uLaw_8kHzStereo ? SPSF_CCITT_uLaw_8kHzStereo : \
format==SPSF_CCITT_uLaw_11kHzMono ? SPSF_CCITT_uLaw_11kHzMono : \
format==SPSF_CCITT_uLaw_11kHzStereo ? SPSF_CCITT_uLaw_11kHzStereo : \
format==SPSF_CCITT_uLaw_22kHzMono ? SPSF_CCITT_uLaw_22kHzMono : \
format==SPSF_CCITT_uLaw_22kHzStereo ? SPSF_CCITT_uLaw_22kHzStereo : \
format==SPSF_CCITT_uLaw_44kHzMono ? SPSF_CCITT_uLaw_44kHzMono : \
format==SPSF_CCITT_uLaw_44kHzStereo ? SPSF_CCITT_uLaw_44kHzStereo : \
// ADPCM formats
format==SPSF_ADPCM_8kHzMono ? SPSF_ADPCM_8kHzMono : \
format==SPSF_ADPCM_8kHzStereo ? SPSF_ADPCM_8kHzStereo : \
format==SPSF_ADPCM_11kHzMono ? SPSF_ADPCM_11kHzMono : \
format==SPSF_ADPCM_11kHzStereo ? SPSF_ADPCM_11kHzStereo : \
format==SPSF_ADPCM_22kHzMono ? SPSF_ADPCM_22kHzMono : \
format==SPSF_ADPCM_22kHzStereo ? SPSF_ADPCM_22kHzStereo : \
format==SPSF_ADPCM_44kHzMono ? SPSF_ADPCM_44kHzMono : \
format==SPSF_ADPCM_44kHzStereo ? SPSF_ADPCM_44kHzStereo : \
// GSM 6.10 formats
format==SPSF_GSM610_8kHzMono ? SPSF_GSM610_8kHzMono : \
format==SPSF_GSM610_11kHzMono ? SPSF_GSM610_11kHzMono : \
format==SPSF_GSM610_22kHzMono ? SPSF_GSM610_22kHzMono : \
format==SPSF_GSM610_44kHzMono ? SPSF_GSM610_44kHzMono : SPSF_NUM_FORMATS)))
{
return (false);
}
lpszF=_ASCIIToWide(fileName);
lpszW=_ASCIIToWide(text);
if (lpszF==NULL || lpszW==NULL)
{
free(lpszF);
free(lpszW);
return (false);
}
if (FAILED(SPBindToFile(lpszF,
SPFM_CREATE_ALWAYS,
&cpStream,
&cAudioFmt.FormatId(),
cAudioFmt.WaveFormatExPtr())))
{
free(lpszF);
free(lpszW);
return (false);
}
if (FAILED(pVoice->SetOutput(cpStream, TRUE)))
{
free(lpszF);
free(lpszW);
return (false);
}
result=(FAILED(pVoice->Speak(lpszW,SPF_DEFAULT, NULL)) ? false : true);
cpStream->Close();
free(lpszF);
free(lpszW);
return (result);
}
DWORD pauseSpeech(void)
{
if (pVoice)
{
return (FAILED(pVoice->Pause() ? false : true));
}
return (false);
}
DWORD resumeSpeech(void)
{
if (pVoice)
{
return (FAILED(pVoice->Resume() ? false : true));
}
return (false);
}
bool __setVoice(int index)
{
HRESULT hr;
voices.m_voiceList.SetCurSel(index);
ISpObjectToken* pToken = SpGetCurSelComboBoxToken(GetDlgItem(voices.m_hWnd, IDC_VOICELIST));
//Determine if it is the current voice
CComPtr pOldToken;
hr = pVoice->GetVoice( &pOldToken );
if (SUCCEEDED(hr))
{
if (pOldToken != pToken)
{
// Stop speaking. This is not necesary, for the next call to work,
// but just to show that we are changing voices.
hr = pVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);
// And set the new voice on the global voice object
if (SUCCEEDED (hr) )
{
hr = pVoice->SetVoice( pToken );
return (true);
}
}
}
return (false);
}
DWORD setVoice(DWORD index)
{
if (pVoice)
{
return (__setVoice(index));
}
return (false);
}
DWORD setVoice(LPSTR voice)
{
if (pVoice)
{
register int iFormat = 0;
register int loop;
register int found;
// Look for the text
found=-1;
for (loop=0; loop=0)
{
// Get the token associated with the selected voice
return (__setVoice(found));
}
}
return (false);
}
// addr+0 - 4 bytes
DWORD getVoices(DWORD addr,DWORD type)
{
register int loop,size;
CString temp;
if (pVoice)
{
size=0;
switch (type) {
case VOICES_GETNUMBER : __pokeL(addr,0,voices.m_voiceList.GetCount());
return (true);
break;
case VOICES_SIZE : if (voices.m_voiceList.GetCount()>0)
{
for (loop=0; loop0)
{
for (loop=0; loopGetStatus(&status,NULL)))
{
__pokeB(addr,0,(DWORD) (status.dwRunningState==SPRS_DONE ? SPEECH_FINISHED : \
status.dwRunningState==SPRS_IS_SPEAKING ? SPEECH_CONTINUING : SPEECH_ABOUTTOSTART));
return (true);
}
}
return (false);
}