SAPI con Dephi: el habla asincrónica no funciona

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.

preguntado el 25 de agosto de 12 a las 00:08

Long time ago I played with SAPI, in order to make it async, I've created a thread with a queue which proved to work quite nice. -

1 Respuestas

Cuando usa el 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 Método

  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.

Respondido 25 ago 12, 18:08

WaitUntilDone turns it into synchronous. So prob not what's needed. Last paragraph could alternatively be stated: if you are using import lib, then you could switch to early binding. +1 - David Heffernan

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.