问题描述
我正在使用这些库:
https://github.com/jimmckeeth/FireMonkey-Android-Voice
https://github.com/FMXExpress/android-object-pascal-wrapper/tree/master/android-25
这是我的源代码:
unit Unit1;
interface
uses
System.SysUtils,System.Types,System.UITypes,System.Classes,System.Variants,FMX.Types,FMX.Controls,FMX.Forms,FMX.Graphics,FMX.Dialogs,SpeechRecognition,FMX.Controls.Presentation,FMX.ScrollBox,FMX.Memo,FMX.StdCtrls,FMX.Memo.Types,AndroidTTS,FMX.Media,System.IoUtils;
type
TForm1 = class(TForm)
SpeechRecognition1: TSpeechRecognition;
Memo1: TMemo;
Button1: TButton;
AndroidTTS1: TAndroidTTS;
Button2: TButton;
Button3: TButton;
Button4: TButton;
MediaPlayer1: TMediaPlayer;
Button5: TButton;
procedure SpeechRecognition1Command(Sender: TObject; Guess: string);
procedure SpeechRecognition1Recognition(Sender: TObject; Guess: string);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
{$R *.NmXhdpiPh.fmx ANDROID}
procedure TForm1.Button1Click(Sender: TObject);
begin
SpeechRecognition1.Prompt := 'What you want?';
SpeechRecognition1.Listen;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
AndroidTTS1.setSpeechRate(0.75);
AndroidTTS1.SpeakVolume('Hello,whats up?',0.75);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
MediaPlayer1.Volume := 0.25;
MediaPlayer1.FileName := TPath.GetDocumentsPath + PathDelim + 'HerosOfLegend.wav';
MediaPlayer1.Play;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
MediaPlayer1.Stop;
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
AndroidTTS1.setSpeechRate(0.75);
AndroidTTS1.SpeakBundle('Hello bundle is this method!');
end;
procedure TForm1.SpeechRecognition1Command(Sender: TObject; Guess: string);
begin
memo1.Lines.Add('Command: ' + Guess);
end;
procedure TForm1.SpeechRecognition1Recognition(Sender: TObject; Guess: string);
begin
memo1.Lines.Add('OnRecognition: ' + Guess);
end;
end.
在https://github.com/jimmckeeth/FireMonkey-Android-Voice/blob/master/JNIBridge/Androidapi.JNI.TTS.pas中的第123行...。我将其更改为:
function speak(text: JString; queueMode: Integer; params: JHashMap) : Integer; cdecl; Overload;
function speak(text: JString; queueMode: Integer; params: JBundle; utteranceId: JString) : Integer; cdecl; Overload;
在https://github.com/jimmckeeth/FireMonkey-Android-Voice/blob/master/Components/AndroidTTS.pas中的第44行上...我将其更改为:
procedure Speak(say: String);
procedure SpeakBundle(say: String);
procedure SpeakVolume(say: String; volume: single);
procedure setPitch(pitch: Single);
procedure setSpeechRate(speechRate: Single);
function isspeaking: Boolean;
在https://github.com/jimmckeeth/FireMonkey-Android-Voice/blob/master/Components/AndroidTTS.pas中的80到97行上……我将其更改为:
procedure TAndroidTTS.SpeakBundle(say: String);
{$IFDEF ANDROID}
var
params: JBundle;
begin
params := nil;
//params := TJHashMap.Create;
//params.put(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,//StringToJString('0.75'));
//params := TJBundle.JavaClass.init();
//params.putFloat(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,volume);
// This needs to be a <String,String> hashmap for the OnDone to work.
{ params := TJHashMap.JavaClass.init();
params.put(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_UTteraNCE_ID,StringToJString('id')); }
ftts.speak(StringToJString(say),TJTextToSpeech.JavaClass.QUEUE_FLUSH,params,StringToJString('1'));
end;
{$ELSE}
begin
end;
{$ENDIF}
procedure TAndroidTTS.SpeakVolume(say: String; volume: single);
{$IFDEF ANDROID}
var
params: JBundle;
begin
//params := TJHashMap.Create;
//params.put(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,//StringToJString('0.75'));
//params := nil;
params := TJBundle.JavaClass.init();
params.putFloat(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,0.75);
// This needs to be a <String,StringToJString('id')); }
//ftts.speak(StringToJString(say),TJTextToSpeech.JavaClass.QUEUE_ADD,StringToJString('1'));
end;
{$ELSE}
begin
end;
{$ENDIF}
procedure TAndroidTTS.setPitch(pitch: Single);
{$IFDEF ANDROID}
begin
//pitch float: Speech pitch. 1.0 is the normal pitch,lower values lower the tone of the synthesized voice,greater values increase it.
ftts.setPitch(pitch);
end;
{$ELSE}
begin
end;
{$ENDIF}
procedure TAndroidTTS.setSpeechRate(speechRate: Single);
{$IFDEF ANDROID}
begin
//float: Speech rate. 1.0 is the normal speech rate,lower values slow down the speech (0.5 is half the normal speech rate),greater values accelerate it (2.0 is twice the normal speech rate).
ftts.setSpeechRate(speechRate);
end;
{$ELSE}
begin
end;
{$ENDIF}
function TAndroidTTS.isspeaking: Boolean;
{$IFDEF ANDROID}
begin
// Checks whether the TTS engine is busy speaking.
result := ftts.isspeaking;
end;
{$ELSE}
begin
result := false;
end;
{$ENDIF}
我似乎无法获得过程TAndroidTTS.SpeakVolume(say:String; volume:single);正常工作。 Android给我一个错误“外部异常1”。与“ params.putFloat(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,0.75);”
我更改并更新了代码以及https://developer.android.com/reference/android/speech/tts/TextToSpeech.Engine#KEY_PARAM_VOLUME,因为他们将其更改为使用Bundles而不是Hashmaps。
我不完全确定 params.putFloat(TJTextToSpeech_Engine.JavaClass.KEY_ParaM_VOLUME,0.75); 出什么问题了。 ...这是Android停止并提供代码的地方。
其他资源:
我已经查看了为什么我的代码使用params.putFloat:
Android text to speech volume not changing
我唯一发现的关于Delphi的错误是:
https://community.idera.com/developer-tools/platforms/f/android-platform/70741/inapppurchase
哪些应该在Delphi 10.4.1中修复,对吗?我检查了https://quality.embarcadero.com/browse/RSP-27140网页,发现该网页已修复。我有其他问题吗?
任何帮助,不胜感激!
解决方法
您收到的异常是因为此导入有错误:
https://github.com/jimmckeeth/FireMonkey-Android-Voice/blob/master/JNIBridge/Androidapi.JNI.TTS.pas
..因为JTextToSpeech_Engine
没有JavaSignature
属性。应该是:
[JavaSignature('android/speech/tts/TextToSpeech$Engine')]
JTextToSpeech_Engine = interface(JObject)
['{5BAC3048-CB0C-4DC4-AF62-D0D9AE4394CF}']
end;
speak方法的重载也不正确。参考:
声明应为:
function speak(text: JCharSequence; queueMode: Integer; params: JBundle; utteranceId: JString): Integer; cdecl; overload;
这样称呼:
ftts.speak(StrToJCharSequence(say),TJTextToSpeech.JavaClass.QUEUE_ADD,params,StringToJString('1'));