Repository: MycroftAI/mycroft-core

Issue:
Extract listener values into configuration
A few options for the listener:
- [ ] Wake word
- [ ] Pronunciations
- [ ] Threshold
- [ ] 3 other listener parameters



Discussion:

Resolving patch:
diff --git a/mycroft/client/speech/listener.py b/mycroft/client/speech/listener.py
--- a/mycroft/client/speech/listener.py
+++ b/mycroft/client/speech/listener.py
@@ -38,6 +38,7 @@
 
 core_config = ConfigurationManager.get().get('core')
 speech_config = ConfigurationManager.get().get('speech_client')
+listener_config = ConfigurationManager.get().get('listener')
 
 
 class AudioProducer(threading.Thread):
@@ -216,11 +217,14 @@ def __init__(self, channels=int(speech_config.get('channels')),
 
     @staticmethod
     def create_mycroft_recognizer(rate, lang):
-        return LocalRecognizer("hey mycroft", "1e-90", rate, lang)
+        wake_word = listener_config.get('wake_word')
+        phonemes = listener_config.get('phonemes')
+        threshold = listener_config.get('threshold')
+        return LocalRecognizer(wake_word, phonemes, threshold, rate, lang)
 
     @staticmethod
     def create_wakeup_recognizer(rate, lang):
-        return LocalRecognizer("wake up", "1e-10", rate, lang)
+        return LocalRecognizer("wake up", "W EY K . AH P", "1e-10", rate, lang)
 
     def start_async(self):
         self.state.running = True
diff --git a/mycroft/client/speech/local_recognizer.py b/mycroft/client/speech/local_recognizer.py
--- a/mycroft/client/speech/local_recognizer.py
+++ b/mycroft/client/speech/local_recognizer.py
@@ -27,19 +27,31 @@
 
 
 class LocalRecognizer(object):
-    def __init__(self, key_phrase, threshold, sample_rate=16000, lang="en-us"):
+    def __init__(self, key_phrase, phonemes, threshold, sample_rate=16000,
+                 lang="en-us"):
         self.lang = lang
         self.key_phrase = key_phrase
         self.sample_rate = sample_rate
         self.threshold = threshold
-        self.decoder = Decoder(self.create_config())
+        self.phonemes = phonemes
+        dict_name = self.create_dict(key_phrase, phonemes)
+        self.decoder = Decoder(self.create_config(dict_name))
 
-    def create_config(self):
+    def create_dict(self, key_phrase, phonemes):
+        folder = os.path.join(BASEDIR, 'model', self.lang)
+        file_name = os.path.join(folder, key_phrase + ".dict")
+        words = key_phrase.split()
+        phoneme_groups = phonemes.split('.')
+        with open(file_name, 'w') as f:
+            for word, phoneme in zip(words, phoneme_groups):
+                f.write(word + ' ' + phoneme + '\n')
+        return file_name
+
+    def create_config(self, dict_name):
         config = Decoder.default_config()
         config.set_string('-hmm', os.path.join(BASEDIR, 'model', self.lang,
                                                'hmm'))
-        config.set_string('-dict', os.path.join(BASEDIR, 'model', self.lang,
-                                                'mycroft-en-us.dict'))
+        config.set_string('-dict', dict_name)
         config.set_string('-keyphrase', self.key_phrase)
         config.set_float('-kws_threshold', float(self.threshold))
         config.set_float('-samprate', self.sample_rate)
diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py
--- a/mycroft/client/speech/mic.py
+++ b/mycroft/client/speech/mic.py
@@ -28,8 +28,11 @@
     AudioData
 )
 import speech_recognition
+
+from mycroft.configuration import ConfigurationManager
 from mycroft.util.log import getLogger
 
+listener_config = ConfigurationManager.get().get('listener')
 logger = getLogger(__name__)
 __author__ = 'seanfitz'
 
@@ -143,6 +146,10 @@ def __init__(self, wake_word_recognizer):
         speech_recognition.Recognizer.__init__(self)
         self.wake_word_recognizer = wake_word_recognizer
         self.audio = pyaudio.PyAudio()
+        self.threshold_multiplier = float(
+            listener_config.get('threshold_multiplier'))
+        self.dynamic_energy_ratio = float(
+            listener_config.get('dynamic_energy_ratio'))
 
     @staticmethod
     def record_sound_chunk(source):
@@ -203,7 +210,8 @@ def decrease_noise(level):
             num_chunks += 1
 
             energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)
-            is_loud = energy > self.energy_threshold
+            test_threshold = self.energy_threshold * self.threshold_multiplier
+            is_loud = energy > test_threshold
             if is_loud:
                 noise = increase_noise(noise)
                 num_loud_chunks += 1
@@ -243,7 +251,7 @@ def wait_until_wake_word(self, source, sec_per_buffer):
             chunk = self.record_sound_chunk(source)
 
             energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)
-            if energy < self.energy_threshold:
+            if energy < self.energy_threshold * self.threshold_multiplier:
                 self.adjust_threshold(energy, sec_per_buffer)
 
             needs_to_grow = len(byte_data) < max_size


Test patch:
diff --git a/audio-accuracy-test/audio_accuracy_test.py b/audio-accuracy-test/audio_accuracy_test.py
--- a/audio-accuracy-test/audio_accuracy_test.py
+++ b/audio-accuracy-test/audio_accuracy_test.py
@@ -7,6 +7,8 @@
 import time
 from os.path import dirname, join
 from speech_recognition import AudioSource
+
+from mycroft.client.speech.listener import RecognizerLoop
 from mycroft.client.speech.local_recognizer import LocalRecognizer
 from mycroft.client.speech.mic import ResponsiveRecognizer
 from mycroft.util.log import getLogger
@@ -75,7 +77,8 @@ def close(self):
 class AudioTester(object):
     def __init__(self, samp_rate):
         print  # Pad debug messages
-        self.ww_recognizer = LocalRecognizer(samp_rate, 'en-us')
+        self.ww_recognizer = RecognizerLoop.create_mycroft_recognizer(
+            samp_rate, 'en-us')
         self.listener = ResponsiveRecognizer(self.ww_recognizer)
         print
         speech_logger.setLevel(100)  # Disables logging to clean output
diff --git a/test/client/audio_consumer_test.py b/test/client/audio_consumer_test.py
--- a/test/client/audio_consumer_test.py
+++ b/test/client/audio_consumer_test.py
@@ -60,7 +60,8 @@ def setUp(self):
             self.loop.state,
             self.queue,
             self.loop,
-            LocalRecognizer(self.loop.wakeup_recognizer.key_phrase, "1e-45"),
+            LocalRecognizer(self.loop.wakeup_recognizer.key_phrase,
+                            self.loop.wakeup_recognizer.phonemes, "1e-16"),
             self.loop.mycroft_recognizer,
             RemoteRecognizerWrapperFactory.wrap_recognizer(
                 self.recognizer, 'google'))
diff --git a/test/client/data/mycroft_wakeup.wav b/test/client/data/mycroft_wakeup.wav
Binary files a/test/client/data/mycroft_wakeup.wav and b/test/client/data/mycroft_wakeup.wav differ