SAPI with Dephi: Async speech doesn't work

delphi, delphi-7, sapi, text-to-speech

Solution

When you uses the SVSFlagsAsync flag, the voice stream is queued in an internal buffer and stay waiting to be executed by the speech service, So I think which you issue is related to the lifetime of the voice object, because is a local variable , the instance is destroyed before to execute the sound.

As workaround you can wait for the sound, using the `WaitUntilDone` method

  voice.Speak (s, SVSFlagsAsync);
  repeat  Sleep(100); until  voice.WaitUntilDone(10);

or declare the `voice` variable in you form definition.

  TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
   voice: OLEVariant;
   procedure SayIt(const s:string);
  end;

var
  MainForm: TMainForm;

implementation

uses
   ComObj;

{$R *.dfm}
procedure TMainForm.SayIt(const s:string); // s is the string to be spoken
const
  SVSFDefault = 0;
  SVSFlagsAsync = 1;
  SVSFPurgeBeforeSpeak= 2;
begin
  memo1.setfocus;
  voice.Voice := voice.GetVoices.Item(combobox1.ItemIndex); // current voice selected
  voice.volume := tbVolume.position;
  voice.rate := tbRate.position;
  voice.Speak (s, SVSFlagsAsync {or SVSFPurgeBeforeSpeak});
end;


procedure TMainForm.Button1Click(Sender: TObject);
begin
  SayIt('Hello');
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  voice := CreateOLEObject('SAPI.SpVoice');
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  voice  := Unassigned;
end;

end.

As additional note, since you are using late binding you don't need the SpeechLib_TLB unit.

Problem

The following works perfectly (Delphi 7): ``` procedure TMainForm.SayIt(s:string); // s is the string to be spoken var voice: OLEVariant; begin memo1.setfocus; voice := CreateOLEObject ('SAPI.SpVoice'); voice.Voice := voice.GetVoices.Item(combobox1.ItemIndex); // current voice selected voice.volume := tbVolume.position; voice.rate := tbRate.position; voice.Speak (s, SVSFDefault); end; ``` The above works in "sync" mode (SVSFDefault flag), but if I change the flag to SVSFlagsAsync in an attempt to play the sound in async mode, no soud is produced. No error messages are given, but nothing is played on the speakers. What might the problem be? I have the SpeechLib_TLB unit in Delphi's Imports folder. EDIT: This is in Windows XP Thanks, Bruno.

Original source