I think I got it, now you can use those DMO FX with SAPI 5. Please test it.
Code: Select all
;/ Speaking from memory using SAPI 5 with FX
;/ By Esteban1 based on the great example
;/ of playing a sound buffer with DirectX 8
;/ (Danilo and www.MasterCreating.de)
;/ and apply DirectX effects on it.
;/ (Zapman)
;/
;/ 08-20-2005
#CLSCTX_INPROC_SERVER = $1
#CLSCTX_INPROC_HANDLER = $2
#CLSCTX_LOCAL_SERVER = $4
#CLSCTX_REMOTE_SERVER = $10
#CLSCTX_ALL = (#CLSCTX_INPROC_SERVER|#CLSCTX_INPROC_HANDLER|#CLSCTX_LOCAL_SERVER|#CLSCTX_REMOTE_SERVER)
#DSBCAPS_PRIMARYBUFFER =$1
#DSBCAPS_LOCSOFTWARE = $8
#DSBCAPS_CTRLFX = $200
#DSFX_LOCSOFTWARE =$2
#DSBLOCK_ENTIREBUFFER = $2
Structure DSFXDesc
dwSize.l
dwFlags.l
guidDSFXClass.GUID
*dwReserved1.l
*dwReserved2.l
EndStructure
Structure WAVEFORMATEX
wFormatTag.w
nChannels.w
nSamplesPerSec.l
nAvgBytesPerSec.l
nBlockAlign.w
wBitsPerSample.w
cbSize.w
EndStructure
Structure DSBUFFERDESC
dwSize.l
dwFlags.l
dwBufferBytes.l
dwReserved.l
*lpwfxFormat.WAVEFORMATEX
guid3DAlgorithm.GUID
EndStructure
Structure VARIANT ; if you have this structure already defined just comment it
vt.w
wReserved1.w
wReserved2.w
wReserved3.w
StructureUnion
bstrVal.l
EndStructureUnion
EndStructure
Interface ISpWaveFormatEx Extends IDispatch
get_FormatTag(a)
put_FormatTag(a)
get_Channels(a)
put_Channels(a)
get_SamplesPerSec(a)
put_SamplesPerSec(a)
get_AvgBytesPerSec(a)
put_AvgBytesPerSec(a)
get_BlockAlign(a)
put_BlockAlign(a)
get_BitsPerSample(a)
put_BitsPerSample(a)
get_ExtraData(a)
put_ExtraData(a,b,c,d)
EndInterface
Interface ISpAudioFormat Extends IDispatch
get_Type(a)
put_Type(a)
get_Guid(a)
put_Guid(a)
GetWaveFormatEx(a)
SetWaveFormatEx(a)
EndInterface
Interface ISpBaseStream Extends IDispatch
get_Format(a)
putref_Format(a)
Read(a,b,c)
Write(a,b,c,d,e)
Seek(a,b,c,d,e,f)
EndInterface
Interface ISpMemoryStream Extends ISpBaseStream
SetData(a,b,c,d)
GetData(a)
EndInterface
Interface ISpVoice Extends IDispatch
get_Status(a)
get_Voice(a)
putref_Voice(a)
get_AudioOutput(a)
putref_AudioOutput(a)
get_AudioOutputStream(a)
putref_AudioOutputStream(a)
get_Rate(a)
put_Rate(a)
get_Volume(a)
put_Volume(a)
put_AllowAudioOutputFormatChangesOnNextSet(a)
get_AllowAudioOutputFormatChangesOnNextSet(a)
get_EventInterests(a)
put_EventInterests(a)
put_Priority(a)
get_Priority(a)
put_AlertBoundary(a)
get_AlertBoundary(a)
put_SynchronousSpeakTimeout(a)
get_SynchronousSpeakTimeout(a)
Speak(a,b,c)
SpeakStream(a,b,c)
Pause()
Resume()
Skip(a,b,c)
GetVoices(a,b,c)
GetAudioOutputs(a,b,c)
WaitUntilDone(a,b)
SpeakCompleteEvent(a)
IsUISupported(a,b,c)
DisplayUI(a,b,c,d)
EndInterface
Procedure SAPI5Init() ; This is just the creation of the voice object.
Shared SAPI5Voice.ISpVoice
CoInitialize_(0)
If CoCreateInstance_(?CLSID_SpVoice, 0, #CLSCTX_ALL, ?IID_ISpVoice, @SAPI5Voice) = 0
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure SAPI5SpeakFX(text.s)
Shared SAPI5Voice.ISpVoice
CoCreateInstance_(?CLSID_SpMemoryStream, 0, #CLSCTX_ALL, ?IID_ISpMemoryStream, @SAPI5Memory.ISpMemoryStream) ; This is the creation of the memory object
text="<voice required="+Chr(34)+"Name=Microsoft Sam"+Chr(34)+"/>"+text ; let's set Sam as the voice
SAPI5Voice\putref_AudioOutputStream(SAPI5Memory) ; we want to send the speech to memory
textlength = Len(text)*2+1 ; just convert ansi string to widechar
*textbuff = AllocateMemory(textlength)
MultiByteToWideChar_(#CP_ACP ,0,text,-1,*textbuff,textlength)
SAPI5Voice\Speak(*textbuff,8,0) ; speak to memory (this is very fast)
FreeMemory(*textbuff) ; free the text buffer
SAPI5Memory\Seek(0,0,0,0,2,@posi.VARIANT) ; get the memory buffer length
membufflength=posi\bstrVal
SAPI5Memory\GetData(@mem.VARIANT) ; get the memory content
If OpenLibrary(0,"DSOUND.DLL") ; now we go for DirectSound
CallFunction(0,"DirectSoundCreate8",0,@DSObject.IDirectSound8,0) ; this is the creation of the DirectSound object
CloseLibrary(0) ; free library
DSObject\SetCooperativeLevel(WindowID(),1) ; now we set the cooperative level
BufferDescriptor.DSBUFFERDESC ; and the structure for the primary buffer
BufferDescriptor\dwSize = SizeOf(DSBUFFERDESC)
BufferDescriptor\dwFlags = #DSBCAPS_PRIMARYBUFFER ; flag for primary buffer
DSObject\CreateSoundBuffer(@BufferDescriptor,@DSPBuffer.IDirectSoundBuffer,0) ; primary buffer creation
SAPI5Memory\get_Format(@SAPI5AudioFormat.ISpAudioFormat) ; get the SpAudioFormat of SAPI5Memory
SAPI5AudioFormat\GetWaveFormatEx(@SAPI5WaveFormatEx.ISpWaveFormatEx) ; and get the SpWaveFormatEx from SpAudioFormat
BufferFormat.WAVEFORMATEX ; here we can put the format information
SAPI5WaveFormatEx\get_FormatTag(@BufferFormat\wFormatTag) ; and put it
SAPI5WaveFormatEx\get_Channels(@BufferFormat\nChannels)
SAPI5WaveFormatEx\get_SamplesPerSec(@BufferFormat\nSamplesPerSec)
SAPI5WaveFormatEx\get_AvgBytesPerSec(@BufferFormat\nAvgBytesPerSec)
SAPI5WaveFormatEx\get_BlockAlign(@BufferFormat\nBlockAlign)
SAPI5WaveFormatEx\get_BitsPerSample(@BufferFormat\wBitsPerSample)
SAPI5WaveFormatEx\get_ExtraData(@BufferFormat\cbSize)
BufferDescriptor\dwFlags = #DSBCAPS_LOCSOFTWARE|#DSBCAPS_CTRLFX ; now the flags for secondary buffer
BufferDescriptor\dwBufferBytes = membufflength-18 ; this is the length of the speech memory buffer
BufferDescriptor\lpwfxFormat = @BufferFormat ; and its format
DSObject\CreateSoundBuffer(@BufferDescriptor,@DSSBuffer.IDirectSoundBuffer,0) ; now we can create the secondary buffer
DSSBuffer\QueryInterface(?IID_DirectSoundBuffer8,@DSSBuffer8.IDirectSoundBuffer8) ; but we need the DirectSoundBuffer8 interface
DSSBuffer\Release() ; we don't need this anymore
DSSBuffer8\Lock(0,0,@lpvWrite,@dwLength,0,0,#DSBLOCK_ENTIREBUFFER) ; now we can start populating the buffer
CopyMemory(mem\bstrVal+18, lpvWrite, membufflength-18) ; copy data from memory buffer to secondary buffer
DSSBuffer8\UnLock(lpvWrite,dwLength,0,0) ; ready
SAPI5Memory\Release() ; not needed too
FXDescriptor.DSFXDesc ; here comes the fx structure
FXDescriptor\dwSize =SizeOf(DSFXDesc)
FXDescriptor\dwFlags=#DSFX_LOCSOFTWARE
; here you set the FX you want, I used CLSID_DirectSoundFXEcho for example, you can find more at the DataSection
CopyMemory(?CLSID_DirectSoundFXEcho,@FXDescriptor\guidDSFXClass,SizeOf(GUID))
DSSBuffer8\SetFX(1,@FXDescriptor, @pdwResultCodes.l) ; now we can set the fx
DSSBuffer8\Play(0,0,0) ; and finally play the buffer
Repeat ; wait until play ends
DSSBuffer8\GetStatus(@Status.l)
Delay(10)
Until Status=0
DSSBuffer8\Stop()
DSSBuffer8\Release() ; and free resources
DSPBuffer\Release()
DSObject\Release()
Else
MessageRequester("Attention!", "DirectSound support not found.", #MB_OK|#MB_ICONWARNING)
EndIf
EndProcedure
Procedure SAPI5End()
Shared SAPI5Voice.ISpVoice
SAPI5Voice\Release() ; free resources
CoUninitialize_()
EndProcedure
DataSection
CLSID_SpVoice:
Data.l $96749377
Data.w $3391,$11D2
Data.b $9E,$E3,$00,$C0,$4F,$79,$73,$96
IID_ISpVoice:
Data.l $269316D8
Data.w $57BD,$11D2
Data.b $9E,$EE,$00,$C0,$4F,$79,$73,$96
CLSID_SpMemoryStream:
Data.l $5FB7EF7D
Data.w $DFF4,$468A
Data.b $B6,$B7,$2F,$CB,$D1,$88,$F9,$94
IID_ISpMemoryStream:
Data.l $EEB14B68
Data.w $808B,$4ABE
Data.b $A5,$EA,$B5,$1D,$A7,$58,$80,$08
IID_DirectSoundBuffer8:
Data.l $6825A449
Data.w $7524,$4D82
Data.b $92,$0F,$50,$E3,$6A,$B3,$AB,$1E
CLSID_DirectSoundFXChorus:
Data.l $EFE6629C
Data.w $81F7,$4281
Data.b $BD,$91,$C9,$D6,$4,$A9,$5A,$F6
CLSID_DirectSoundFXFlanger:
Data.l $EFCA3D92
Data.w $DFD8,$4672
Data.b $A6,$3,$74,$20,$89,$4B,$AD,$98
CLSID_DirectSoundFXEcho:
Data.l $EF3E932C
Data.w $D40B,$4F51
Data.b $8C,$CF,$3F,$98,$F1,$B2,$9D,$5D
CLSID_DirectSoundFXDistortion:
Data.l $EF114C90
Data.w $CD1D,$484E
Data.b $96,$E5,$9,$CF,$AF,$91,$2A,$21
CLSID_DirectSoundFXCompressor:
Data.l $EF011F79
Data.w $4000,$406D
Data.b $87,$AF,$BF,$FB,$3F,$C3,$9D,$57
CLSID_DirectSoundFXEqualization:
Data.l $120CED89
Data.w $3BF4,$4173
Data.b $A1,$32,$3C,$B4,$6,$CF,$32,$31
CLSID_DirectSoundFXI3DL2Reverberation:
Data.l $EF985E71
Data.w $D5C7,$42D4
Data.b $BA,$4D,$2D,$7,$3E,$2E,$96,$F4
CLSID_DirectSoundFXWReverberation:
Data.l $87FC0268
Data.w $9A55,$4360
Data.b $95,$AA,$0,$4A,$1D,$9D,$E2,$6C
EndDataSection
;/ Let's test it
OpenWindow(0,0,0,200,200,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"Speech DMO FX")
CreateGadgetList(WindowID())
ButtonGadget(0,80,80,40,40,"Speak")
If SAPI5Init()
Else
MessageRequester("Error!", "Unable to initialize SAPI 5 support.", #MB_OK|#MB_ICONERROR)
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Quit = 1
Case #PB_Event_Gadget
Select EventGadgetID()
Case 0
SAPI5SpeakFX("Hello world!")
SAPI5SpeakFX("I'm using some effects.")
SAPI5SpeakFX("Goodbye!")
EndSelect
EndSelect
Until Quit
SAPI5End()
End