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