@@ -18,14 +18,47 @@ public class Speech : MonoBehaviour
18
18
// singleton isntance
19
19
public static Speech instance ;
20
20
21
+ public delegate void TTSCallback ( string message , AudioClip audio ) ;
22
+
23
+ public enum IncomingMessageType {
24
+ Say ,
25
+ SetRate ,
26
+ SetVolume ,
27
+ SetPitch ,
28
+ SetRange ,
29
+ SetWordGap ,
30
+ SetCapitals ,
31
+ SetIntonation ,
32
+ SetVoice ,
33
+ }
34
+ public class IncomingMessage {
35
+ public IncomingMessageType type ;
36
+ public int param1 ;
37
+ public string message ;
38
+ public TTSCallback callback ;
39
+ }
40
+
41
+
21
42
// queue for tts strings
22
- Queue < string > messages = new Queue < string > ( ) ;
43
+ Mutex message_mutex = new Mutex ( ) ;
44
+ Queue < IncomingMessage > messages = new Queue < IncomingMessage > ( ) ;
23
45
bool isClosing = false ;
24
46
bool isRunning = false ;
25
47
26
- Mutex audio_list_mutex = new Mutex ( ) ;
27
- List < float [ ] > audio_files = new List < float [ ] > ( ) ;
28
- public AudioSource audio_source ;
48
+
49
+ enum OutgoingMessageType {
50
+ VoiceLineFinished ,
51
+ }
52
+
53
+ class OutgoingMessage {
54
+ public OutgoingMessageType type ;
55
+ public string message ;
56
+ public float [ ] data ;
57
+ public TTSCallback callback ;
58
+ }
59
+
60
+ Mutex outgoing_message_mutex = new Mutex ( ) ;
61
+ Queue < OutgoingMessage > outgoing_messages = new Queue < OutgoingMessage > ( ) ;
29
62
30
63
void Awake ( )
31
64
{
@@ -47,80 +80,181 @@ void Awake()
47
80
48
81
void SpeakerThread ( )
49
82
{
50
- isRunning = true ;
51
- while ( isClosing == false )
52
- {
53
- if ( messages . Count > 0 )
54
- {
83
+ bool waiting_for_line = false ;
84
+ string message_waited_for = "" ;
85
+ TTSCallback callback_waited_for = null ;
86
+ SetIsRunning ( true ) ;
87
+ while ( IsClosing ( ) == false ) {
88
+ if ( waiting_for_line ) {
89
+ if ( Client . VoiceFinished ( ) ) {
90
+ byte [ ] new_voice = Client . PopVoice ( ) ;
91
+ float [ ] voice_float = new float [ new_voice . Length / 2 ] ;
92
+
93
+ for ( int i = 0 ; i < voice_float . Length ; i ++ ) {
94
+ //if(BitConverter.IsLittleEndian)
95
+ voice_float [ i ] = ( float ) BitConverter . ToInt16 ( new_voice , i * 2 ) / ( float ) short . MaxValue ;
96
+ }
97
+ OutgoingMessage om = new OutgoingMessage ( ) ;
98
+ om . type = OutgoingMessageType . VoiceLineFinished ;
99
+ om . data = voice_float ;
100
+ om . message = message_waited_for ;
101
+ om . callback = callback_waited_for ;
102
+
103
+ outgoing_message_mutex . WaitOne ( ) ;
104
+ outgoing_messages . Enqueue ( om ) ;
105
+ outgoing_message_mutex . ReleaseMutex ( ) ;
106
+ waiting_for_line = false ;
107
+ message_waited_for = "" ;
108
+ callback_waited_for = null ;
109
+ }
110
+ } else if ( HasMessage ( ) ) {
55
111
try
56
112
{
57
- var msg = messages . Dequeue ( ) ;
58
-
59
- Client . Speak ( msg ) ;
60
-
61
- // could use SSML also
62
- //Client.SpeakSSML(msg);
63
- if ( Client . VoiceFinished ( ) ) {
64
- byte [ ] new_voice = Client . PopVoice ( ) ;
65
- float [ ] voice_float = new float [ new_voice . Length / 2 ] ;
66
-
67
- for ( int i = 0 ; i < voice_float . Length ; i ++ ) {
68
- //if(BitConverter.IsLittleEndian)
69
- voice_float [ i ] = ( float ) BitConverter . ToInt16 ( new_voice , i * 2 ) / ( float ) short . MaxValue ;
70
- }
71
- audio_list_mutex . WaitOne ( ) ;
72
- audio_files . Add ( voice_float ) ;
73
- audio_list_mutex . ReleaseMutex ( ) ;
113
+ IncomingMessage msg = PopMessage ( ) ;
114
+ switch ( msg . type ) {
115
+ case IncomingMessageType . Say :
116
+ Client . Speak ( msg . message ) ;
117
+ //Client.SpeakSSML(msg);
118
+
119
+ message_waited_for = msg . message ;
120
+ callback_waited_for = msg . callback ;
121
+ waiting_for_line = true ;
122
+ break ;
123
+ case IncomingMessageType . SetPitch :
124
+ Client . SetPitch ( msg . param1 ) ;
125
+ break ;
126
+ case IncomingMessageType . SetRange :
127
+ Client . SetRange ( msg . param1 ) ;
128
+ break ;
129
+ case IncomingMessageType . SetRate :
130
+ Client . SetRate ( msg . param1 ) ;
131
+ break ;
132
+ case IncomingMessageType . SetVolume :
133
+ Client . SetVolume ( msg . param1 ) ;
134
+ break ;
135
+ case IncomingMessageType . SetWordGap :
136
+ Client . SetWordgap ( msg . param1 ) ;
137
+ break ;
138
+ case IncomingMessageType . SetCapitals :
139
+ Client . SetCapitals ( msg . param1 ) ;
140
+ break ;
141
+ case IncomingMessageType . SetIntonation :
142
+ Client . SetIntonation ( msg . param1 ) ;
143
+ break ;
144
+ case IncomingMessageType . SetVoice :
145
+ Client . SetVoiceByName ( msg . message ) ;
146
+ break ;
147
+
74
148
}
75
149
}
76
150
catch ( System . Exception e )
77
151
{
78
152
Debug . LogException ( e ) ;
79
153
}
80
154
}
81
- else
82
- {
83
- Thread . Sleep ( 16 ) ;
84
- }
155
+
156
+ Thread . Sleep ( 8 ) ;
85
157
}
86
158
isRunning = false ;
87
159
}
88
160
89
161
// adds string to TTS queue
90
- public void Say ( string msg )
162
+ public void Say ( string msg , TTSCallback callback )
91
163
{
92
- if ( isClosing == true || isRunning == false ) return ;
164
+ if ( IsClosing ( ) == true || IsRunning ( ) == false ) return ;
93
165
if ( string . IsNullOrEmpty ( msg ) ) return ;
94
166
95
- messages . Enqueue ( msg ) ;
167
+ IncomingMessage im = new IncomingMessage ( ) ;
168
+ im . type = IncomingMessageType . Say ;
169
+ im . message = msg ;
170
+ im . callback = callback ;
171
+ QueueMessage ( im ) ;
172
+ }
173
+
174
+ public void QueueMessage ( IncomingMessage im ) {
175
+ message_mutex . WaitOne ( ) ;
176
+ messages . Enqueue ( im ) ;
177
+ message_mutex . ReleaseMutex ( ) ;
178
+ }
179
+
180
+ private bool HasMessage ( )
181
+ {
182
+ bool ret = false ;
183
+ message_mutex . WaitOne ( ) ;
184
+ if ( messages . Count > 0 ) {
185
+ ret = true ;
186
+ }
187
+ message_mutex . ReleaseMutex ( ) ;
188
+ return ret ;
189
+ }
190
+
191
+ private IncomingMessage PopMessage ( ) {
192
+ IncomingMessage im = null ;
193
+ message_mutex . WaitOne ( ) ;
194
+ if ( messages . Count > 0 ) {
195
+ im = messages . Dequeue ( ) ;
196
+ }
197
+ message_mutex . ReleaseMutex ( ) ;
198
+ return im ;
199
+ }
200
+
201
+ public void SetIsClosing ( bool val ) {
202
+ message_mutex . WaitOne ( ) ;
203
+ isClosing = val ;
204
+ message_mutex . ReleaseMutex ( ) ;
205
+ }
206
+
207
+ public void SetIsRunning ( bool val ) {
208
+ message_mutex . WaitOne ( ) ;
209
+ isRunning = val ;
210
+ message_mutex . ReleaseMutex ( ) ;
211
+ }
212
+
213
+ public bool IsClosing ( ) {
214
+ bool val = false ;
215
+ message_mutex . WaitOne ( ) ;
216
+ val = isClosing ;
217
+ message_mutex . ReleaseMutex ( ) ;
218
+ return val ;
219
+ }
220
+
221
+ public bool IsRunning ( ) {
222
+ bool val = false ;
223
+ message_mutex . WaitOne ( ) ;
224
+ val = isRunning ;
225
+ message_mutex . ReleaseMutex ( ) ;
226
+ return val ;
96
227
}
97
228
98
229
public void Update ( )
99
230
{
100
- float [ ] data = null ;
101
- audio_list_mutex . WaitOne ( ) ;
102
- Debug . Log ( audio_files . Count ) ;
103
- if ( audio_files . Count > 0 ) {
104
- data = audio_files [ 0 ] ;
105
- audio_files . RemoveAt ( 0 ) ;
231
+ OutgoingMessage om = null ;
232
+ outgoing_message_mutex . WaitOne ( ) ;
233
+ if ( outgoing_messages . Count > 0 ) {
234
+ om = outgoing_messages . Dequeue ( ) ;
106
235
}
107
- audio_list_mutex . ReleaseMutex ( ) ;
108
- if ( data != null ) {
109
- AudioClip ac = AudioClip . Create ( "voice" , data . Length , 1 , Client . sampleRate , false ) ;
110
- ac . SetData ( data , 0 ) ;
111
- audio_source . clip = ac ;
112
- audio_source . loop = true ;
113
- audio_source . Play ( ) ;
236
+ outgoing_message_mutex . ReleaseMutex ( ) ;
237
+ if ( om != null ) {
238
+ AudioClip ac = AudioClip . Create ( "voice" , om . data . Length , 1 , Client . sampleRate , false ) ;
239
+ ac . SetData ( om . data , 0 ) ;
240
+ om . callback ( om . message , ac ) ;
114
241
}
115
242
}
116
243
117
244
private void OnDestroy ( )
118
245
{
119
246
Client . Stop ( ) ;
120
- isClosing = true ;
247
+ SetIsClosing ( true ) ;
121
248
249
+ int wait_counter = 2000 ;
122
250
// NOTE this will hang unity, until speech has stopped (otherwise crash)
123
- while ( isRunning ) { } ;
251
+ while ( IsRunning ( ) ) {
252
+ Thread . Sleep ( 1 ) ;
253
+ if ( wait_counter -- < 0 ) {
254
+ Debug . LogError ( "Sound system dindn't shut down in time." ) ;
255
+ break ;
256
+ }
257
+ } ;
124
258
}
125
259
126
260
} // class
0 commit comments