Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 062e434

Browse files
committed
Rewrite library communications routine
1 parent c297e15 commit 062e434

File tree

4 files changed

+261
-61
lines changed

4 files changed

+261
-61
lines changed

‎Assets/Libraries/eSpeakWrapper/Client.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,60 @@ public static bool SetRate(int rate)
106106
throw new Exception("The rate must be between 80 and 450.");
107107
}
108108

109-
var result = espeak_SetParameter(Parameter.Rate, rate, ParameterType.Absolute);
109+
Error result = espeak_SetParameter(Parameter.Rate, rate, ParameterType.Absolute);
110+
return CheckResult(result);
111+
}
112+
113+
public static bool SetRange(int range) {
114+
if(range < 0) {
115+
range = 0;
116+
}
117+
if(range > 100) {
118+
range = 100;
119+
}
120+
121+
Error result = espeak_SetParameter(Parameter.Range, range, ParameterType.Absolute);
122+
return CheckResult(result);
123+
}
124+
125+
public static bool SetPitch(int pitch) {
126+
if(pitch < 0) {
127+
pitch = 0;
128+
}
129+
if(pitch > 100) {
130+
pitch = 100;
131+
}
132+
133+
Error result = espeak_SetParameter(Parameter.Pitch, pitch, ParameterType.Absolute);
134+
return CheckResult(result);
135+
}
136+
137+
public static bool SetWordgap(int wordgap) {
138+
if(wordgap < 0) {
139+
wordgap = 0;
140+
}
141+
Error result = espeak_SetParameter(Parameter.WordGap, wordgap, ParameterType.Absolute);
142+
return CheckResult(result);
143+
}
144+
145+
public static bool SetVolume(int volume) {
146+
if(volume < 0) {
147+
volume = 0;
148+
}
149+
if(volume > 200) {
150+
volume = 200;
151+
}
152+
Error result = espeak_SetParameter(Parameter.Volume, volume, ParameterType.Absolute);
153+
return CheckResult(result);
154+
}
155+
156+
public static bool SetIntonation(int intonation) {
157+
Error result = espeak_SetParameter(Parameter.Intonation, intonation, ParameterType.Absolute);
158+
return CheckResult(result);
159+
}
160+
161+
public static bool SetCapitals(int capitals) {
162+
Error result = espeak_SetParameter(Parameter.Capitals, capitals, ParameterType.Absolute);
110163
return CheckResult(result);
111164
}
112165

‎Assets/Libraries/eSpeakWrapper/EventHandler.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class EventHandler
2121

2222
public static int Handle(IntPtr wavePtr, int bufferLength, IntPtr eventsPtr)
2323
{
24-
Console.WriteLine("Received event!");
25-
Console.WriteLine("Buffer length is " + bufferLength);
24+
//Console.WriteLine("Received event!");
25+
//Console.WriteLine("Buffer length is " + bufferLength);
2626

2727
// crash, but console log gets printed to output.log
2828
//Debug.Log("Buffer length is " + bufferLength);
@@ -36,17 +36,19 @@ public static int Handle(IntPtr wavePtr, int bufferLength, IntPtr eventsPtr)
3636

3737
//PlayAudio();
3838
//Console.Write(ConvertHeadersToString(Stream.GetBuffer()));
39-
40-
Stream.Flush();
41-
audio_files_mutex.WaitOne();
42-
audio_files.Add(Stream.ToArray());
43-
audio_files_mutex.ReleaseMutex();
44-
Stream.Dispose();
39+
if(Stream != null) {
40+
Stream.Flush();
41+
audio_files_mutex.WaitOne();
42+
audio_files.Add(Stream.ToArray());
43+
audio_files_mutex.ReleaseMutex();
44+
Stream.Dispose();
45+
Stream = null;
46+
}
4547
return 0;
48+
} else {
49+
WriteAudioToStream(wavePtr, bufferLength);
4650
}
4751

48-
WriteAudioToStream(wavePtr, bufferLength);
49-
5052
var events = MarshalEvents(eventsPtr);
5153

5254
foreach (Event anEvent in events)

‎Assets/Scripts/Speech.cs

Lines changed: 182 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,47 @@ public class Speech : MonoBehaviour
1818
// singleton isntance
1919
public static Speech instance;
2020

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+
2142
// queue for tts strings
22-
Queue<string> messages = new Queue<string>();
43+
Mutex message_mutex = new Mutex();
44+
Queue<IncomingMessage> messages = new Queue<IncomingMessage>();
2345
bool isClosing = false;
2446
bool isRunning = false;
2547

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>();
2962

3063
void Awake()
3164
{
@@ -47,80 +80,181 @@ void Awake()
4780

4881
void SpeakerThread()
4982
{
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()) {
55111
try
56112
{
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+
74148
}
75149
}
76150
catch (System.Exception e)
77151
{
78152
Debug.LogException(e);
79153
}
80154
}
81-
else
82-
{
83-
Thread.Sleep(16);
84-
}
155+
156+
Thread.Sleep(8);
85157
}
86158
isRunning = false;
87159
}
88160

89161
// adds string to TTS queue
90-
public void Say(string msg)
162+
public void Say(string msg,TTSCallbackcallback)
91163
{
92-
if (isClosing == true || isRunning == false) return;
164+
if (IsClosing() == true || IsRunning() == false) return;
93165
if (string.IsNullOrEmpty(msg)) return;
94166

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;
96227
}
97228

98229
public void Update()
99230
{
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();
106235
}
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);
114241
}
115242
}
116243

117244
private void OnDestroy()
118245
{
119246
Client.Stop();
120-
isClosing=true;
247+
SetIsClosing(true);
121248

249+
int wait_counter = 2000;
122250
// 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+
};
124258
}
125259

126260
} // class

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /