Posted: 30th Jan 2003 1:15
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.

+ Code Snippet
// 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);
}
Posted: 4th Feb 2003 20:35
... i see your a newbie, Reece.
Posted: 4th Feb 2003 20:57
It won't work in anything - it didn't post right

MrTAToad: Check out the includes at the top. The memory.h is needed too.
Posted: 5th Feb 2003 16:16
I never actually said it would compile you know...
Posted: 5th Feb 2003 19:37
LOL

Why not just zip it all up and let people get it from your site instead?
Posted: 5th Feb 2003 19:47
I think its easier for everyone to just post the main code here...
Posted: 5th Feb 2003 19:49
Yes, Reece, it can work in DB 'Classic' as long as you have DarkMatter. You would need the function names for it though...
Posted: 7th Feb 2003 4:43
now that's C if I ever saw it
Posted: 7th Feb 2003 10:22
Yes - its certainly not very BASIC...