Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Warten bis Sprachausgabe beendet (https://www.delphipraxis.net/177054-warten-bis-sprachausgabe-beendet.html)

Amateurprofi 13. Okt 2013 14:48

Warten bis Sprachausgabe beendet
 
Ich möchte per Sprachausgabe einen Text ausgeben und solange warten, bis entweder der Text komplett gesprochen wurde, oder irgendeine Taste gedrückt wird.
Wenn der Text komplett gesprochen wurde, möchte ich einen Timer "enablen", und den Text nach einer gewissen Wartezeit erneut ausgeben.
Wurde aber durch Drücken einer Taste abgebrochen, soll der Timer nicht "enabled" werden.

Mein untenstehender Versuch, zunächst einmal zu warten, bis entweder der Text komplett gesprochen wurde, oder eine Taste gedrückt wurde, funktioniert nicht, weil das MsgWaitForMultipleObjects zurückkehrt, bevor der Text komplett gesprochen wurde, auch wenn keine Taste gedrückt wurde.

Wie kann ich das realisieren?
Und Frage am Rande: Muss ich Voice beim beenden des Programms irgenwie "freigeben" oder brauche ich mich darum nicht kümmern?

Delphi-Quellcode:
procedure TMain.FormShow(Sender: TObject);
begin
   Voice:=CreateOleObject('SAPI.SpVoice');
end;

procedure TMain.Button1Click(Sender: TObject);
var Reason:Cardinal; Ev:THandle;
begin
   Edit1.Text:='';
   Application.ProcessMessages;
   Voice.Speak('Hallo, ich warte jetzt, bis der Text zu ende ist, oder eine '+
               'Taste gedrückt wird.', 1);
   Ev:=Voice.SpeakCompleteEvent;
   Reason:=MsgWaitForMultipleObjects(1, Ev, False, Infinite, QS_Key);
   Edit1.Text:=IntToStr(Reason);
end;

Gerd01 13. Okt 2013 16:41

AW: Warten bis Sprachausgabe beendet
 
Du könntest die SpeechLib_TLB.pas benutzen.
Dort ist das Server-Object
// ************************************************** *******************//
// OLE-Server-Proxy-Klassendeklaration
// Server-Objekt : TSpVoice
// Hilfe-String : SpVoice Class
// Standard-Interface: ISpeechVoice
// Def. Intf. DISP? : No
// Ereignis-Interface: _ISpeechVoiceEvents
// TypeFlags : (2) CanCreate
// ************************************************** *******************//

TSpVoice = class(TOleServer)

Mit SpVoice1.Skip('Sentence', MaxInt) kannst du die Sprachausgabe stoppen
Mit SpVoice1.Pause pausieren etc. Der OleServer läßt keine Wünsche offen.

Amateurprofi 13. Okt 2013 21:30

AW: Warten bis Sprachausgabe beendet
 
@Gerd01:
Danke, jedoch leider löst das nicht mein Problem.
Ich möchte nicht die Ausgabe der Sprache beenden, pausieren etc.
Sondern ich möchte solange warten, bis
entweder der zu sprechende Text komplett gesprochen wurde
oder eine Taste gedrückt wurde.
Und ich brauche eine Information, ob "das Warten" beendet wurde, weil der Text komplett gesprochen wurde oder weil eine Taste gedrückt wurde.

BUG 14. Okt 2013 15:37

AW: Warten bis Sprachausgabe beendet
 
Dein Code entspricht ja ziemlich genau dem Beispiel von Microsoft.
Funktioniert es* denn, wenn du mit WaitUntilDone oder WaitForSingleObject wartest bzw. was ist der Rückgabewert von MsgWaitForMultipleObjects?

* Damit meine ich natürlich nur das Warten auf die Sprachausgaben :stupid:

Amateurprofi 14. Okt 2013 23:33

AW: Warten bis Sprachausgabe beendet
 
@Bug:
WaitUntilDone
funktioniert, wartet also bis entweder der Text gesprochen ist, oder die als Parameter mitgegebene Zeit abgelaufen ist.

WaitForSingleObject
dto

MsgWaitForMultipleObjects
Der Rückgabewert ist immer = 1

BUG 15. Okt 2013 00:01

AW: Warten bis Sprachausgabe beendet
 
Das bedeutet imho, dass dein Problem beim Aufwecken durch den Tastendruck (QS_Key) liegt und nicht bei der Sprachausgabe.

Eventuell könnte man es so beheben:
Delphi-Quellcode:
procedure TMain.Button1Click(Sender: TObject);
var Reason:Cardinal; Ev:THandle;
begin
   Edit1.Text:='';
   Application.ProcessMessages;
   Voice.Speak('Hallo, ich warte jetzt, bis der Text zu ende ist, oder eine '+
               'Taste gedrückt wird.', 1);
   Ev:=Voice.SpeakCompleteEvent;
   // >>>
   speechCanceled := false; // "global"
   repeat
     Reason:=MsgWaitForMultipleObjects(1, Ev, False, Infinite, QS_Key);
     if Reason = (WAIT_OBJECT_0 + 1) then
       Application.ProcessMessages;
   until speechCanceled or (Reason = WAIT_OBJECT_0);
   // <<<
   Edit1.Text:=IntToStr(Reason);
end;
speechCanceled könnte dann bei Bedarf (also einer gewünschten Tasten-Aktion) in der Message-Behandlung des Formulars gesetzt werden.

Amateurprofi 15. Okt 2013 03:29

AW: Warten bis Sprachausgabe beendet
 
@Bug:
Das wird so nicht funktionieren, weil (zumindest bei mir) MsgWaitForMultipleObjects sofort zurückkehrt und konstant 1 als Resultat liefert. Zum Drücken einer Taste kommt es also gar nicht.

Ich habe mein Problem jetzt so gelöst:

Delphi-Quellcode:
PROCEDURE TMain.Speak(Const S:String);
var Res:DWord; EV:THandle;
begin
   Timer.Enabled:=False;
   Voice.Skip('SENTENCE',MaxInt);
   fSpeakCancelled:=False;
   Voice.Speak(S,1);
   EV:=Voice.SpeakCompleteEvent;
   repeat
      Res:=WaitForSingleObject(Ev,100);
      if Res=WAIT_TIMEOUT then Application.Processmessages;
   until (Res<>WAIT_TIMEOUT) or SpeakCancelled;
   if not SpeakCancelled then Timer.Enabled:=True;
end;
fSpeakCancelled wird in FormShortCut dann auf True gesetzt, wenn eine Taste gedrückt wird.
Mit Voice.WaitUntilDone klappte das merkwürdigerweise nicht.
Danke für Deinen Hinweis auf WaitForSingleObject, das ich von vornherein verworfen hatte.
Da ich ja nicht nur auf das Ende der Sprachausgabe sondern parallel auch auf Tastendrücke warten wollte war ich auf MsgWaitForMultipleObjects fixiert.

Gerd01 15. Okt 2013 09:15

AW: Warten bis Sprachausgabe beendet
 
Zitat:

Zitat von Amateurprofi (Beitrag 1231939)
@Gerd01:
Danke, jedoch leider löst das nicht mein Problem.
Ich möchte nicht die Ausgabe der Sprache beenden, pausieren etc.
Sondern ich möchte solange warten, bis
entweder der zu sprechende Text komplett gesprochen wurde
oder eine Taste gedrückt wurde.
Und ich brauche eine Information, ob "das Warten" beendet wurde, weil der Text komplett gesprochen wurde oder weil eine Taste gedrückt wurde.

Ja ich verstehe schon was du meinst. Folgende Ereignisse
stehen bei der Komponente aber zur Verfügung:


property OnStartStream: TSpVoiceStartStream read FOnStartStream write FOnStartStream;
property OnEndStream: TSpVoiceEndStream read FOnEndStream write FOnEndStream;
property OnVoiceChange: TSpVoiceVoiceChange read FOnVoiceChange write FOnVoiceChange;
property OnBookmark: TSpVoiceBookmark read FOnBookmark write FOnBookmark;
property OnWord: TSpVoiceWord read FOnWord write FOnWord;
property OnSentence: TSpVoiceSentence read FOnSentence write FOnSentence;
property OnPhoneme: TSpVoicePhoneme read FOnPhoneme write FOnPhoneme;
property OnViseme: TSpVoiceViseme read FOnViseme write FOnViseme;
property OnAudioLevel: TSpVoiceAudioLevel read FOnAudioLevel write FOnAudioLevel;
property OnEnginePrivate: TSpVoiceEnginePrivate read FOnEnginePrivate write FOnEnginePrivate;

Amateurprofi 15. Okt 2013 22:16

AW: Warten bis Sprachausgabe beendet
 
Danke, Gerd.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz