我正在尝试创建一个简单的应用程序来使用 Delphi10 处理接收到的 BLE 数据: -Win10 -德尔福11 -从“onecore”目录导入SAPI(我只在这个目录下找到中文引擎)
代码很简单:
unit unitTTS;
interface
uses
SpeechLib_TLB,
globalDefinitions,
System.Generics.Collections, System.Generics.Defaults,
FMX.Dialogs,
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants;
type
SPEAKFLAGS = (
//--- SpVoice flags
SPF_DEFAULT,
SPF_ASYNC,
SPF_PURGEBEFORESPEAK,
SPF_IS_FILENAME,
SPF_IS_XML,
SPF_IS_NOT_XML,
SPF_PERSIST_XML,
//--- Normalizer flags
SPF_NLP_SPEAK_PUNC,
//--- TTS Format
SPF_PARSE_SAPI,
SPF_PARSE_SSML,
SPF_PARSE_AUTODETECT,
//--- Masks
SPF_NLP_MASK,
SPF_PARSE_MASK,
SPF_VOICE_MASK,
SPF_UNUSED_FLAGS
);
TextFlags=(
TXTF_SCORE,
TXTF_TIMEOUT,
TXTF_OTHER
);
TmyTTS = class
private
FSpVoice:TSpVoice;
function initCNSpeech(AOwner: TComponent):Boolean;
public
constructor Create(AOwner: TComponent);
destructor Destroy;override;
procedure speak(s:string;txtf:TextFlags);
procedure SetRate(v:integer);
procedure SetVolume(v:integer);
end;
var
tts : TmyTTS;
implementation
procedure TmyTTS.speak(s:string;txtf:TextFlags);
var
flags:LongWord;
cb:LongWord;
pStatus: SPVOICESTATUS;
ppszLastBookmark: PWideChar;
begin
//exit;
if FSpVoice = NIL then exit;
if length(trim(s))=0 then exit;
FSpVoice.GetStatus(pStatus,ppszLastBookmark);
if pStatus.dwRunningState = 2 then
case txtf of
TXTF_SCORE: FSpVoice.Speak('',2,cb);
TXTF_TIMEOUT: exit;
TXTF_OTHER: exit;
end;
flags := LongWord(SPF_ASYNC);
cb := 0;
//不能使用@s,因为下标从1开始,0位置存储字符串长度,必须明确标出开始位置
FSpVoice.Speak(@s[1],flags,cb);
end;
constructor TmyTTS.Create(AOwner: TComponent);
begin
Inherited Create;
initCNSpeech(AOwner);
end;
destructor TmyTTS.Destroy;
begin
FreeAndNIL(FSpVoice);
Inherited;
end;
procedure TmyTTS.SetRate(v:integer);
begin
if FSpVoice = NIL then exit;
FSpVoice.SetRate(v);
end;
procedure TmyTTS.SetVolume(v:integer);
begin
if FSpVoice = NIL then exit;
FSpVoice.SetVolume(v);
end;
function TmyTTS.initCNSpeech(AOwner: TComponent):Boolean;
var
cnt:longword ;
tok : ISpObjectToken;
toks:IEnumSpObjectTokens;
ppTokenCategory: ISpObjectTokenCategory;
begin
Result := false;
FSpVoice := TSpVoice.Create(AOwner);
FSpVoice.GetVoice(&tok);
tok.GetCategory(&ppTokenCategory);
ppTokenCategory.EnumTokens('language=804',nil,&toks);
toks.GetCount(cnt);
if cnt=0 then
begin
showmessage('没有中文语音生成引擎.');
FSpVoice.Free;
exit;
end;
toks.Item(0,tok);
FSpVoice.SetVoice(tok);
result := true;
end;
end.
调用起来也很简单:
tts.speak(s,TXTF_SCORE);
我遇到的问题是:
tts.SetRate(trunc(TTrackBar(Sender).Value));
但我可以用 OS GUI 更改它,它会反映在播放中。我尝试在线程中启动speack(),但没有帮助。
原因应该是异步模式设置的优先级太低。 我创建了一个最高优先级的不间断线程,它也可以顺利完成播放(不如同步模式)。 这是代码:
TSpeechThread = class(TThread)
private
procedure delFirstString;
protected
procedure Execute; override;
public
constructor Create;
end;
constructor TSpeechThread.Create;
begin
Inherited Create(True);
Priority:=tpTimeCritical;
FreeOnTerminate:=false;
end;
procedure TSpeechThread.delFirstString;
begin
if tts.FStrings.Count>0 then
tts.FStrings.Delete(0);
end;
procedure TSpeechThread.Execute;
begin
while(true) do
if not Terminated then
begin
if tts.FStrings<>NIL then
begin
if tts.FStrings.Count>0 then
begin
tts.speak(tts.FStrings[0],TXTF_SCORE);
synchronize(delFirstString);
end
else
suspend;
end;
end
else
break;
end;
合作代码:
procedure TmyTTS.addSentence(s:string);
begin
FStrings.Add(s);
if (speechThread<>NIL) then
if speechThread.Suspended then
speechThread.Resume;
end;
但是,我仍然无法改变语速。 欢迎任何建议。