audio_accuracy_test.py
Go to the documentation of this file.
1 # Copyright 2017 Mycroft AI Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15 import time
16 import wave
17 from glob import glob
18 
19 import os
20 import pyee
21 from os.path import dirname, join
22 from speech_recognition import AudioSource
23 
24 from mycroft.client.speech.listener import RecognizerLoop
25 from mycroft.client.speech.mic import ResponsiveRecognizer
26 
27 
28 def to_percent(val):
29  return "{0:.2f}".format(100.0 * val) + "%"
30 
31 
32 class FileStream:
33  MIN_S_TO_DEBUG = 5.0
34 
35  # How long between printing debug info to screen
36  UPDATE_INTERVAL_S = 1.0
37 
38  def __init__(self, file_name):
39  self.file = wave.open(file_name, 'rb')
40  self.size = self.file.getnframes()
41  self.sample_rate = self.file.getframerate()
42  self.sample_width = self.file.getsampwidth()
43  self.last_update_time = 0.0
44 
45  self.total_s = self.size / self.sample_rate / self.sample_width
46  if self.total_s > self.MIN_S_TO_DEBUG:
47  self.debug = True
48  else:
49  self.debug = False
50 
51  def calc_progress(self):
52  return float(self.file.tell()) / self.size
53 
54  def read(self, chunk_size):
55 
56  progress = self.calc_progress()
57  if progress == 1.0:
58  raise EOFError
59 
60  if self.debug:
61  cur_time = time.time()
62  dt = cur_time - self.last_update_time
63  if dt > self.UPDATE_INTERVAL_S:
64  self.last_update_time = cur_time
65  print(to_percent(progress))
66 
67  return self.file.readframes(chunk_size)
68 
69  def close(self):
70  self.file.close()
71 
72 
73 class FileMockMicrophone(AudioSource):
74  def __init__(self, file_name):
75  self.stream = FileStream(file_name)
76  self.SAMPLE_RATE = self.stream.sample_rate
77  self.SAMPLE_WIDTH = self.stream.sample_width
78  self.CHUNK = 1024
79 
80  def close(self):
81  self.stream.close()
82 
83 
85  def __init__(self, samp_rate):
86  print() # Pad debug messages
87  self.ww_recognizer = RecognizerLoop().create_mycroft_recognizer(
88  samp_rate, 'en-us')
90  print()
91 
92  def test_audio(self, file_name):
93  source = FileMockMicrophone(file_name)
94  ee = pyee.EventEmitter()
95 
96  class SharedData:
97  times_found = 0
98 
99  def on_found_wake_word():
100  SharedData.times_found += 1
101 
102  ee.on('recognizer_loop:record_begin', on_found_wake_word)
103 
104  try:
105  while True:
106  self.listener.listen(source, ee)
107  except EOFError:
108  pass
109 
110  return SharedData.times_found
111 
112 
113 class Color:
114  BOLD = '\033[1m'
115  NORMAL = '\033[0m'
116  GREEN = '\033[92m'
117  RED = '\033[91m'
118 
119 
120 def bold_str(val):
121  return Color.BOLD + str(val) + Color.NORMAL
122 
123 
125  return dirname(dirname(__file__))
126 
127 
128 def get_file_names(folder):
129  query = join(folder, '*.wav')
130  root_dir = get_root_dir()
131  full_path = join(root_dir, query)
132  file_names = sorted(glob(full_path))
133 
134  if len(file_names) < 1:
135  raise IOError
136 
137  return file_names
138 
139 
140 def test_audio_files(tester, file_names, on_file_finish):
141  num_found = 0
142  for file_name in file_names:
143  short_name = os.path.basename(file_name)
144  times_found = tester.test_audio(file_name)
145 
146  num_found += times_found
147  on_file_finish(short_name, times_found)
148 
149  return num_found
150 
151 
152 def file_frame_rate(file_name):
153  wf = wave.open(file_name, 'rb')
154  frame_rate = wf.getframerate()
155  wf.close()
156  return frame_rate
157 
158 
159 def print_ww_found_status(word, short_name):
160  print("Wake word " + bold_str(word) + " - " + short_name)
161 
162 
163 def test_false_negative(directory):
164  file_names = get_file_names(directory)
165 
166  # Grab audio format info from first file
167  tester = AudioTester(file_frame_rate(file_names[0]))
168 
169  def on_file_finish(short_name, times_found):
170  not_found_str = Color.RED + "Not found"
171  found_str = Color.GREEN + "Detected "
172  status_str = not_found_str if times_found == 0 else found_str
173  print_ww_found_status(status_str, short_name)
174 
175  num_found = test_audio_files(tester, file_names, on_file_finish)
176  total = len(file_names)
177 
178  print
179  print("Found " + bold_str(num_found) + " out of " + bold_str(total))
180  print(bold_str(to_percent(float(num_found) / total)) + " accuracy.")
181  print
182 
183 
184 def test_false_positive(directory):
185  file_names = get_file_names(directory)
186 
187  # Grab audio format info from first file
188  tester = AudioTester(file_frame_rate(file_names[0]))
189 
190  def on_file_finish(short_name, times_found):
191  not_found_str = Color.GREEN + "Not found"
192  found_str = Color.RED + "Detected "
193  status_str = not_found_str if times_found == 0 else found_str
194  print_ww_found_status(status_str, short_name)
195 
196  num_found = test_audio_files(tester, file_names, on_file_finish)
197  total = len(file_names)
198 
199  print
200  print("Found " + bold_str(num_found) + " false positives")
201  print("in " + bold_str(str(total)) + " files")
202  print
203 
204 
205 def run_test():
206  directory = join('audio-accuracy-test', 'data')
207 
208  false_neg_dir = join(directory, 'with_wake_word', 'query_after')
209  false_pos_dir = join(directory, 'without_wake_word')
210 
211  try:
212  test_false_negative(false_neg_dir)
213  except IOError:
214  print(bold_str("Warning: No wav files found in " + false_neg_dir))
215 
216  try:
217  test_false_positive(false_pos_dir)
218  except IOError:
219  print(bold_str("Warning: No wav files found in " + false_pos_dir))
220 
221  print("Complete!")
222 
223 
224 if __name__ == "__main__":
225  run_test()
def test_audio_files(tester, file_names, on_file_finish)
def print_ww_found_status(word, short_name)
def test_false_positive(directory)
def file_frame_rate(file_name)
def test_false_negative(directory)


mycroft_ros
Author(s):
autogenerated on Mon Apr 26 2021 02:35:40