-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSentenceEvaluator.cs
More file actions
219 lines (190 loc) · 7.54 KB
/
SentenceEvaluator.cs
File metadata and controls
219 lines (190 loc) · 7.54 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/*
* @Author: Sean Rannie
* @Date: Mar/19/2019
*
* This script contains a pair of classes that evaluates sentences
*/
public class Sentence
{
private Queue<float> _avgVolumeSamples; //The avg volume over the course of the sentence
private Queue<float> _volumeSamples; //The volume over the course of the sentence
private double _startTime; //The starting time of the sentence
private double _endTime; //The ending time of the sentence
//Constructor
public Sentence(double start)
{
_avgVolumeSamples = new Queue<float>();
_volumeSamples = new Queue<float>();
_startTime = start;
_endTime = -1;
Debug.Log("Sentence Starting");
}
//Marks the end of the sentence
public void EndSentence(double end)
{
//Can only end sentence once
if (IsEnded())
{
_endTime = end;
Debug.Log("Sentence Concluded (" + _avgVolumeSamples.Count + " samples)");
}
}
//Indication that the sentence has ended
public bool IsEnded() { return _endTime == -1; }
//Difference in time from when the sentence started and ended
public double ElapsedTime
{
get { return _endTime - _startTime; }
}
//Data can be streamed in and out of the chart queue
public float StreamChart
{
get { return _avgVolumeSamples.Dequeue(); }
set { _avgVolumeSamples.Enqueue(value); }
}
//Sets the samples of the audio
public Queue<float> Samples
{
get { return _volumeSamples; }
set
{
while (value.Count > 0)
_volumeSamples.Enqueue(value.Dequeue());
}
}
//The size of the sample chart is retrieved
public int SampleSize
{
get { return _avgVolumeSamples.Count; }
}
}
public class SentenceEvaluator: MonoBehaviour
{
private static float _VOLUME_SILENCE = 0.008f;//Minimum to be considered silent
[Header("Set in Inspector")]
public Text prompt; //Text that is written to
public string triggeredText = "Sentence has been paused!";
public string untriggeredText = "Sentence is fine!";
public string filename = "SEN #"; //The filename that is used for creating .wav file
public int volumeScale = 4; //Vertical scale of the graph (may get overwritten)
public float minSilenceTime = 0.75f;//The minimum time needed to declare that the sentence is broken
public float maxSilenceTime = 1.5f; //The maximum time needed for the speech to be considered paused for too long
public bool writeToWAV = true; //Creates .wav files of sentence
public bool debug = false; //Whether information should be written to the console
private LinkedList<Sentence> _sentences = new LinkedList<Sentence>(); //The recorded sentences
private float _silenceTimer = 0; //The time accumulated from silence
private int _sampleRate; //Sample rate of audio
private int _writtenSentences = 0; //Number of sentences written to .wav file
private bool _breakFlag = false; //Triggered when the sentence ends
private bool _pauseFlag = false; //Triggered when the speaker pauses too long
private bool _sentenceStart = false;//Triggered when the sentence starts
private bool _recordedFlag = false; //Triggered when the sentence is recorded
//Starting method
public void Start()
{
if (GetComponent<MicrophoneReader>() != null)
GetComponent<MicrophoneReader>().SetSenetenceEvaluator(this);
else
Debug.LogError("ERROR: SentenceEvaluator added to object without microphone listener.");
}
//Evaluates both the average and collectino of samples
public void Evaluate(float avg, Queue<float> sampleList)
{
if(_sentences.Count > 0)
_sentences.Last.Value.Samples = sampleList;
//If volume is below silence threshold
if (avg < _VOLUME_SILENCE)
{
_silenceTimer += Time.deltaTime;
//If silence time has reached minimum threshold
if (_silenceTimer > minSilenceTime)
{
_breakFlag = true;
_sentenceStart = false;
if (_sentences.Count > 0)
{
_sentences.Last.Value.EndSentence(_silenceTimer);
if (writeToWAV)
{
_writtenSentences++;
string s = AudioWriter.WriteToWAV(filename + _writtenSentences + ".wav", _sampleRate, _sentences.Last.Value.Samples);
Debug.Log("Sentence successfully written to " + s);
Debug.Log("# of samples = " + _sentences.Last.Value.Samples.Count);
}
}
}
//If silent for too long
if (_silenceTimer > maxSilenceTime)
{
_pauseFlag = true;
prompt.text = triggeredText;
}
else
prompt.text = untriggeredText;
}
//If sound is detected
else
{
_silenceTimer = 0;
_breakFlag = _pauseFlag = false;
//If sentence hasn't been started
if (!_sentenceStart)
{
_sentences.AddLast(new Sentence(_silenceTimer));
_sentenceStart = true;
}
_sentences.Last.Value.StreamChart = avg;
}
}
//Draws the last sentence on a texture canvas
public void DrawSentenceGraph(Texture2D canvas, int x1, int y1, int x2, int y2)
{
//If sentence needs to be recorded
if (_sentences.Count > 0 && !(_sentenceStart || _recordedFlag))
{
int graphWidth = x2 - x1;
int graphHeight = y2 - y1;
int samples = _sentences.Last.Value.SampleSize;
int rate = samples / graphWidth;
int iRate = graphWidth / samples + 1;
float total = 0;
//Fill waveform graph
if (rate < 1) //More pixels than samples
for (int x = 0; x < graphWidth; x++)
{
if (x % iRate == 0)
total = _sentences.First.Value.StreamChart;
for (int s = 0; s < graphHeight / 2; s++)
{
if (s < Mathf.Abs(total * graphHeight * volumeScale))
canvas.SetPixel(x, s, Color.blue);
else
canvas.SetPixel(x, s, Color.white);
}
}
else //More samples than pixels
for (int x = 0; x < graphWidth; x++, total = 0)
{
for (int i = 0; i < rate; i++)
total += _sentences.First.Value.StreamChart;
for (int s = 0; s < graphHeight / 2; s++)
{
if (s < Mathf.Abs(total / rate * graphHeight * volumeScale))
canvas.SetPixel(x, s, Color.blue);
else
canvas.SetPixel(x, s, Color.white);
}
}
//Sentence has been recorded
_sentences.RemoveFirst();
_recordedFlag = true;
}
else if (_sentenceStart)
_recordedFlag = false;
}
public int SampleRate { set { _sampleRate = value; } }
public bool Flag { get { return _pauseFlag; } }
}