-
Notifications
You must be signed in to change notification settings - Fork 66
/
Copy pathGrijjy.TextToSpeech.macOS.pas
134 lines (115 loc) · 3.78 KB
/
Grijjy.TextToSpeech.macOS.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
unit Grijjy.TextToSpeech.macOS;
{< Text To Speech engine implementation for macOS }
interface
uses
Macapi.AppKit,
Macapi.ObjectiveC,
Grijjy.TextToSpeech.Base;
type
{ The declaration of NSSpeechSynthesizerDelegate in Macapi.AppKit is
incomplete. So we add the events we are interested in here. }
NSSpeechSynthesizerDelegateEx = interface(NSSpeechSynthesizerDelegate)
['{D0AE9338-9D9B-4857-A404-255F40E4EB09}']
[MethodName('speechSynthesizer:willSpeakPhoneme:')]
procedure speechSynthesizerWillSpeakPhoneme(sender: NSSpeechSynthesizer;
phonemeOpcode: Smallint); cdecl;
[MethodName('speechSynthesizer:didFinishSpeaking:')]
procedure speechSynthesizerDidFinishSpeaking(sender: NSSpeechSynthesizer;
finishedSpeaking: Boolean); cdecl;
end;
type
{ IgoSpeechToText implementation }
TgoTextToSpeechImplementation = class(TgoTextToSpeechBase)
{$REGION 'Internal Declarations'}
private type
TDelegate = class(TOCLocal, NSSpeechSynthesizerDelegate, NSSpeechSynthesizerDelegateEx)
private
FTextToSpeech: TgoTextToSpeechImplementation;
FStartedSpeaking: Boolean;
public
constructor Create(const ATextToSpeech: TgoTextToSpeechImplementation);
public
{ AVSpeechSynthesizerDelegate }
[MethodName('speechSynthesizer:willSpeakPhoneme:')]
procedure speechSynthesizerWillSpeakPhoneme(sender: NSSpeechSynthesizer;
phonemeOpcode: Smallint); cdecl;
[MethodName('speechSynthesizer:didFinishSpeaking:')]
procedure speechSynthesizerDidFinishSpeaking(sender: NSSpeechSynthesizer;
finishedSpeaking: Boolean); cdecl;
end;
private
FSpeechSynthesizer: NSSpeechSynthesizer;
FDelegate: NSSpeechSynthesizerDelegateEx;
protected
{ IgoTextToSpeech }
function Speak(const AText: String): Boolean; override;
procedure Stop; override;
function IsSpeaking: Boolean; override;
{$ENDREGION 'Internal Declarations'}
public
constructor Create;
destructor Destroy; override;
end;
implementation
uses
Macapi.Helpers;
{ TgoTextToSpeechImplementation }
constructor TgoTextToSpeechImplementation.Create;
begin
inherited Create;
FSpeechSynthesizer := TNSSpeechSynthesizer.Create;
if (FSpeechSynthesizer <> nil) then
begin
FDelegate := TDelegate.Create(Self);
FSpeechSynthesizer.setDelegate(FDelegate);
Available := True;
end;
end;
destructor TgoTextToSpeechImplementation.Destroy;
begin
if (FSpeechSynthesizer <> nil) then
FSpeechSynthesizer.release;
inherited;
end;
function TgoTextToSpeechImplementation.IsSpeaking: Boolean;
begin
Result := (FSpeechSynthesizer <> nil) and (FSpeechSynthesizer.isSpeaking);
end;
function TgoTextToSpeechImplementation.Speak(const AText: String): Boolean;
begin
if (FSpeechSynthesizer = nil) then
Result := False
else
Result := FSpeechSynthesizer.startSpeakingString(StrToNSStr(AText));
end;
procedure TgoTextToSpeechImplementation.Stop;
begin
if (FSpeechSynthesizer <> nil) then
FSpeechSynthesizer.stopSpeaking;
end;
{ TgoTextToSpeechImplementation.TDelegate }
constructor TgoTextToSpeechImplementation.TDelegate.Create(
const ATextToSpeech: TgoTextToSpeechImplementation);
begin
Assert(Assigned(ATextToSpeech));
inherited Create;
FTextToSpeech := ATextToSpeech;
end;
procedure TgoTextToSpeechImplementation.TDelegate.speechSynthesizerDidFinishSpeaking(
sender: NSSpeechSynthesizer; finishedSpeaking: Boolean);
begin
FStartedSpeaking := False;
if Assigned(FTextToSpeech) then
FTextToSpeech.DoSpeechFinished;
end;
procedure TgoTextToSpeechImplementation.TDelegate.speechSynthesizerWillSpeakPhoneme(
sender: NSSpeechSynthesizer; phonemeOpcode: Smallint);
begin
if (not FStartedSpeaking) then
begin
FStartedSpeaking := True;
if Assigned(FTextToSpeech) then
FTextToSpeech.DoSpeechStarted;
end;
end;
end.