unit winsapi;
{
partial sapi.h conversion for the syntesized voice functions
https://www.w3.org/TR/speech-synthesis/
works:
hello
this wil freeze it(for a too long time)
hello
}
{$mode objfpc}{$H+}
interface
uses
windows, Classes, SysUtils, ole2, variants, ActiveX, comobj;
function speak(s: widestring; waittilldone: boolean=false): HRESULT; overload;
function speak(s: widestring; flags: dword): HRESULT; overload;
const
CLSID_SpVoice: TGUID = (D1:$96749377;D2:$3391;D3:$11D2;D4:($9e,$e3,$00,$c0,$4f,$79,$73,$96));
SPF_DEFAULT = 0;
SPF_ASYNC = ( 1 shl 0 );
SPF_PURGEBEFORESPEAK = ( 1 shl 1 );
SPF_IS_FILENAME = ( 1 shl 2 ) ;
SPF_IS_XML = ( 1 shl 3 ) ;
SPF_IS_NOT_XML = ( 1 shl 4 );
SPF_PERSIST_XML = ( 1 shl 5 );
SPF_NLP_SPEAK_PUNC = ( 1 shl 6 );
SPF_PARSE_SAPI = ( 1 shl 7 );
SPF_PARSE_SSML = ( 1 shl 8 );
SPF_PARSE_AUTODETECT = 0;
SPF_NLP_MASK = SPF_NLP_SPEAK_PUNC;
SPF_PARSE_MASK = ( SPF_PARSE_SAPI or SPF_PARSE_SSML );
SPF_VOICE_MASK = ( ( ( ( ( ( ( SPF_ASYNC or SPF_PURGEBEFORESPEAK ) or SPF_IS_FILENAME ) or SPF_IS_XML ) or SPF_IS_NOT_XML ) or SPF_NLP_MASK ) or SPF_PERSIST_XML ) or SPF_PARSE_MASK );
SPF_UNUSED_FLAGS = not SPF_VOICE_MASK;
type
SPVPRIORITY=(SPVPRI_NORMAL=0, SPVPRI_ALERT=1, SPVPRI_OVER=2);
SPEVENTENUM=(SPEI_UNDEFINED = 0,
SPEI_START_INPUT_STREAM = 1,
SPEI_END_INPUT_STREAM = 2,
SPEI_VOICE_CHANGE = 3,
SPEI_TTS_BOOKMARK = 4,
SPEI_WORD_BOUNDARY = 5,
SPEI_PHONEME = 6,
SPEI_SENTENCE_BOUNDARY = 7,
SPEI_VISEME = 8,
SPEI_TTS_AUDIO_LEVEL = 9,
SPEI_TTS_PRIVATE = 15,
SPEI_MIN_TTS = 1,
SPEI_MAX_TTS = 15,
SPEI_END_SR_STREAM = 34,
SPEI_SOUND_START = 35,
SPEI_SOUND_END = 36,
SPEI_PHRASE_START = 37,
SPEI_RECOGNITION = 38,
SPEI_HYPOTHESIS = 39,
SPEI_SR_BOOKMARK = 40,
SPEI_PROPERTY_NUM_CHANGE = 41,
SPEI_PROPERTY_STRING_CHANGE = 42,
SPEI_FALSE_RECOGNITION = 43,
SPEI_INTERFERENCE = 44,
SPEI_REQUEST_UI = 45,
SPEI_RECO_STATE_CHANGE = 46,
SPEI_ADAPTATION = 47,
SPEI_START_SR_STREAM = 48,
SPEI_RECO_OTHER_CONTEXT = 49,
SPEI_SR_AUDIO_LEVEL = 50,
SPEI_SR_RETAINEDAUDIO = 51,
SPEI_SR_PRIVATE = 52,
SPEI_ACTIVE_CATEGORY_CHANGED = 53,
SPEI_RESERVED5 = 54,
SPEI_RESERVED6 = 55,
SPEI_MIN_SR = 34,
SPEI_MAX_SR = 55,
SPEI_RESERVED1 = 30,
SPEI_RESERVED2 = 33,
SPEI_RESERVED3 = 63);
SPEVENT=record
eEventId: WORD;
elParamType: WORD;
ulStreamNum: ULONG;
ullAudioStreamOffset: ULONGLONG;
wParam: wParam;
lParam: lParam;
end;
PSPEVENT=^SPEVENT;
SPEVENTSOURCEINFO=record
ullEventInterest: ULONGLONG;
ullQueuedInterest: ULONGLONG;
ulCount: ULONG;
end;
PSPEVENTSOURCEINFO=^SPEVENTSOURCEINFO;
SPVOICESTATUS = record
ulCurrentStream: ULONG;
ulLastStreamQueued: ULONG;
hrLastResult: HRESULT;
dwRunningState: DWORD;
ulInputWordPos: ULONG;
ulInputWordLen: ULONG;
ulInputSentPos: ULONG;
ulInputSentLen: ULONG;
lBookmarkId: LONG;
PhonemeId: WORD;
VisemeId: WORD;
dwReserved1: DWORD;
dwReserved2: DWORD;
end;
SPNOTIFYCALLBACK=procedure(wParam: WPARAM; lParam: LPARAM); stdcall;
ISpDataKey = interface (IUnknown)
['{14056581-E16C-11D2-BB90-00C04F8EE6C0}']
{
virtual HRESULT STDMETHODCALLTYPE SetData(
/* [in] */ LPCWSTR pszValueName,
/* [in] */ ULONG cbData,
/* [in] */ const BYTE *pData) = 0;
virtual HRESULT STDMETHODCALLTYPE GetData(
/* [in] */ LPCWSTR pszValueName,
/* [in] */ ULONG *pcbData,
/* [out] */ BYTE *pData) = 0;
virtual HRESULT STDMETHODCALLTYPE SetStringValue(
/* [in][annotation] */
_In_opt_ LPCWSTR pszValueName,
/* [in] */ LPCWSTR pszValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStringValue(
/* [in][annotation] */
_In_opt_ LPCWSTR pszValueName,
/* [out][annotation] */
_Outptr_ LPWSTR *ppszValue) = 0;
virtual HRESULT STDMETHODCALLTYPE SetDWORD(
/* [in] */ LPCWSTR pszValueName,
/* [in] */ DWORD dwValue) = 0;
virtual HRESULT STDMETHODCALLTYPE GetDWORD(
/* [in] */ LPCWSTR pszValueName,
/* [out] */ DWORD *pdwValue) = 0;
virtual HRESULT STDMETHODCALLTYPE OpenKey(
/* [in] */ LPCWSTR pszSubKeyName,
/* [out][annotation] */
_Outptr_ ISpDataKey **ppSubKey) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateKey(
/* [in] */ LPCWSTR pszSubKey,
/* [out][annotation] */
_Outptr_ ISpDataKey **ppSubKey) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteKey(
/* [in] */ LPCWSTR pszSubKey) = 0;
virtual HRESULT STDMETHODCALLTYPE DeleteValue(
/* [in] */ LPCWSTR pszValueName) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumKeys(
/* [in] */ ULONG Index,
/* [out][annotation] */
_Outptr_ LPWSTR *ppszSubKeyName) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumValues(
/* [in] */ ULONG Index,
/* [out][annotation] */
_Outptr_ LPWSTR *ppszValueName) = 0;
}
end;
ISpObjectToken = interface (ISpDataKey)
['{14056589-E16C-11D2-BB90-00C04F8EE6C0}']
{
virtual HRESULT STDMETHODCALLTYPE SetId(
/* [annotation] */
_In_opt_ LPCWSTR pszCategoryId,
/* [in] */ LPCWSTR pszTokenId,
/* [in] */ BOOL fCreateIfNotExist) = 0;
virtual HRESULT STDMETHODCALLTYPE GetId(
/* [out][annotation] */
_Outptr_ LPWSTR *ppszCoMemTokenId) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCategory(
/* [out][annotation] */
_Outptr_ ISpObjectTokenCategory **ppTokenCategory) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateInstance(
/* [in] */ IUnknown *pUnkOuter,
/* [in] */ DWORD dwClsContext,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStorageFileName(
/* [in] */ REFCLSID clsidCaller,
/* [annotation][in] */
_In_ LPCWSTR pszValueName,
/* [string][in][annotation] */
_In_opt_ LPCWSTR pszFileNameSpecifier,
/* [in] */ ULONG nFolder,
/* [out][annotation] */
_Outptr_ LPWSTR *ppszFilePath) = 0;
virtual HRESULT STDMETHODCALLTYPE RemoveStorageFileName(
/* [in] */ REFCLSID clsidCaller,
/* [in][annotation] */
_In_ LPCWSTR pszKeyName,
/* [in] */ BOOL fDeleteFile) = 0;
virtual HRESULT STDMETHODCALLTYPE Remove(
/* [annotation] */
_In_opt_ const CLSID *pclsidCaller) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE IsUISupported(
/* [in] */ LPCWSTR pszTypeOfUI,
/* [in] */ void *pvExtraData,
/* [in] */ ULONG cbExtraData,
/* [in] */ IUnknown *punkObject,
/* [out] */ BOOL *pfSupported) = 0;
virtual /* [local] */ HRESULT STDMETHODCALLTYPE DisplayUI(
/* [in] */ HWND hwndParent,
/* [in] */ LPCWSTR pszTitle,
/* [in] */ LPCWSTR pszTypeOfUI,
/* [in] */ void *pvExtraData,
/* [in] */ ULONG cbExtraData,
/* [in] */ IUnknown *punkObject) = 0;
virtual HRESULT STDMETHODCALLTYPE MatchesAttributes(
/* [in] */ LPCWSTR pszAttributes,
/* [out] */ BOOL *pfMatches) = 0;
}
end;
PISpObjectToken = ^ISpObjectToken;
ISpStreamFormat = interface(IStream)
['{BED530BE-2606-4F4D-A1C0-54C5CDA5566F}']
function GetFormat(pguidFormatId: GUID; out ppCoMemWaveFormatEx: TWAVEFORMATEX): HRESULT; stdcall;
end;
PISpStreamFormat = ^ISpStreamFormat;
ISpNotifySink = interface (IUnknown)
['{259684DC-37C3-11D2-9603-00C04F8EE628}']
function Notify: HRESULT; stdcall;
end;
ISpNotifySource = interface (IUnknown)
['{5EFF4AEF-8487-11D2-961C-00C04F8EE628}']
function SetNotifySink(NotifySink: ISpNotifySink): HRESULT; stdcall;
function SetNotifyWindowMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): HRESULT; stdcall;
function SetNotifyCallbackFunction(pfnCallback: SPNOTIFYCALLBACK; wParam: WPARAM; lParam: LPARAM): HRESULT; stdcall;
function SetNotifyCallbackInterface(pSpCallback: pointer; wParam: WPARAM; lParam: LPARAM): HRESULT; stdcall;
function SetNotifyWin32Event: HRESULT; stdcall;
function WaitForNotifyEvent(dwMilliseconds: DWORD): HRESULT; stdcall;
function GetNotifyEventHandle: HANDLE; stdcall;
end;
ISpEventSource = interface (ISpNotifySource)
['{BE7A9CCE-5F9E-11D2-960F-00C04F8EE628}']
function SetInterest(ullEventInterest: ULONGLONG; ullQueuedInterest: ULONGLONG): HRESULT; stdcall;
function GetEvents(ulCount: ULONG; pEventArray: PSPEVENT; out pulFetched: ULONG): HRESULT; stdcall;
function GetInfo(pInfo: PSPEVENTSOURCEINFO): HRESULT; stdcall;
end;
ISpVoice = Interface (ISpEventSource)
['{6C44DF74-72B9-4992-A1EC-EF996E0422D4}']
function SetOutput(pUnkOutput: IUnknown; fAllowFormatChanges: BOOL): HRESULT; stdcall;
function GetOutputObjectToken(out ppObjectToken: ISpObjectToken): HRESULT; stdcall;
function GetOutputStream(out ppStream: ISpStreamFormat): HRESULT; stdcall;
function Pause: HRESULT; stdcall;
function Resume: HRESULT; stdcall;
function SetVoice(pToken: ISpObjectToken): HRESULT; stdcall;
function GetVoice(out pToken: ISpObjectToken): HRESULT; stdcall;
function Speak(pwcs: PWCHAR; dwFlags: DWORD; pulStreamNumber: PULONG): HRESULT; stdcall;
function SpeakStream(pStream: IStream; dwFlags: DWORD; pulStreamNumber: PULONG): HRESULT; stdcall;
function GetStatus(out pStatus: SPVOICESTATUS; out ppszLastBookmark: pwchar): HRESULT; stdcall;
function Skip(pItemType: LPCWSTR; lNumItems: long; out ulNumSkipped: ULONG): HRESULT; stdcall;
function SetPriority(ePriority: SPVPRIORITY): HRESULT; stdcall;
function GetPriority(out ePriority: SPVPRIORITY): HRESULT; stdcall;
function SetAlertBoundary(ePriority: SPEVENTENUM): HRESULT; stdcall;
function GetAlertBoundary(out ePriority: SPEVENTENUM): HRESULT; stdcall;
function SetRate(RateAdjust: long): HRESULT; stdcall;
function GetRate(out RateAdjust: long): HRESULT; stdcall;
function SetVolume(RateAdjust: USHORT): HRESULT; stdcall;
function GetVolume(out RateAdjust: USHORT): HRESULT; stdcall;
function WaitUntilDone(msTimeout: ULONG): HRESULT; stdcall;
function SetSyncSpeakTimeout(msTimeout: ULONG): HRESULT; stdcall;
function GetSyncSpeakTimeout(out msTimeout: ULONG): HRESULT; stdcall;
function SpeakCompleteEvent: HRESULT; stdcall;
function IsUISupported(pszTypeOfUI: LPCWSTR; pvExtraData: pointer; cbExtraData: ULONG; out fSupported: BOOL): HRESULT; stdcall;
function DisplayUI(hwndParent: HWND; pszTitle: LPCWSTR; pszTypeOfUI: LPCWSTR; pvExtraData: pointer; cbExtraData: ULONG): HRESULT; stdcall;
end;
implementation
var
voice: ISpVoice;
novoice: boolean=false;
function speak(s: widestring; flags: dword): HRESULT;
var
sn: ulong;
begin
{
for c users reading this code, and wondering why I don't call _release.
FPC will call _Release automatically when the reference count is nil
}
if not assigned(voice) then
begin
try
voice:=ISpVoice(CreateComObject(CLSID_SpVoice));
except
exit(-1);
end;
end;
if assigned(voice) then
result:=voice.Speak(pwchar(s), flags, nil);
end;
function speak(s: widestring; waitTillDone: boolean=false): HRESULT; overload;
var flags: dword;
begin
flags:=SPF_PURGEBEFORESPEAK;
if not waittilldone then
flags:=flags or SPF_ASYNC;
result:=speak(s, flags);
end;
end.