We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Listener waits too long and too often for more sound
Often when saying short queries in which the listener hasn't detected enough total noise it sits there waiting for more when in fact you are actually done speaking. To resolve this we should decrease the minimum seconds of noise and put a limit to how long it will wait (perhaps 3-4 seconds).


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mycroft/client/speech/mic.py`
Content:
```
1 # Copyright 2016 Mycroft AI, Inc.
2 #
3 # This file is part of Mycroft Core.
4 #
5 # Mycroft Core is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Mycroft Core is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 import collections
20 import audioop
21 from time import sleep
22 
23 import pyaudio
24 from speech_recognition import (
25     Microphone,
26     AudioSource,
27     WaitTimeoutError,
28     AudioData
29 )
30 import speech_recognition
31 from mycroft.util.log import getLogger
32 
33 logger = getLogger(__name__)
34 __author__ = 'seanfitz'
35 
36 
37 class MutableStream(object):
38     def __init__(self, wrapped_stream, format, muted=False):
39         assert wrapped_stream is not None
40         self.wrapped_stream = wrapped_stream
41         self.muted = muted
42         self.SAMPLE_WIDTH = pyaudio.get_sample_size(format)
43         self.muted_buffer = b''.join([b'\x00' * self.SAMPLE_WIDTH])
44 
45     def mute(self):
46         self.muted = True
47 
48     def unmute(self):
49         self.muted = False
50 
51     def read(self, size):
52         frames = collections.deque()
53         remaining = size
54         while remaining > 0:
55             to_read = min(self.wrapped_stream.get_read_available(), remaining)
56             if to_read == 0:
57                 sleep(.01)
58                 continue
59             result = self.wrapped_stream.read(to_read)
60             frames.append(result)
61             remaining -= to_read
62 
63         if self.muted:
64             return self.muted_buffer
65         input_latency = self.wrapped_stream.get_input_latency()
66         if input_latency > 0.2:
67             logger.warn("High input latency: %f" % input_latency)
68         audio = b"".join(list(frames))
69         return audio
70 
71     def close(self):
72         self.wrapped_stream.close()
73         self.wrapped_stream = None
74 
75     def is_stopped(self):
76         return self.wrapped_stream.is_stopped()
77 
78     def stop_stream(self):
79         return self.wrapped_stream.stop_stream()
80 
81 
82 class MutableMicrophone(Microphone):
83     def __init__(self, device_index=None, sample_rate=16000, chunk_size=1024):
84         Microphone.__init__(
85             self, device_index=device_index, sample_rate=sample_rate,
86             chunk_size=chunk_size)
87         self.muted = False
88 
89     def __enter__(self):
90         assert self.stream is None, \
91             "This audio source is already inside a context manager"
92         self.audio = pyaudio.PyAudio()
93         self.stream = MutableStream(self.audio.open(
94             input_device_index=self.device_index, channels=1,
95             format=self.format, rate=self.SAMPLE_RATE,
96             frames_per_buffer=self.CHUNK,
97             input=True,  # stream is an input stream
98         ), self.format, self.muted)
99         return self
100 
101     def __exit__(self, exc_type, exc_value, traceback):
102         if not self.stream.is_stopped():
103             self.stream.stop_stream()
104         self.stream.close()
105         self.stream = None
106         self.audio.terminate()
107 
108     def mute(self):
109         self.muted = True
110         if self.stream:
111             self.stream.mute()
112 
113     def unmute(self):
114         self.muted = False
115         if self.stream:
116             self.stream.unmute()
117 
118 
119 class ResponsiveRecognizer(speech_recognition.Recognizer):
120     # The maximum audio in seconds to keep for transcribing a phrase
121     # The wake word must fit in this time
122     SAVED_WW_SEC = 1.0
123 
124     # Padding of silence when feeding to pocketsphinx
125     SILENCE_SEC = 0.01
126 
127     # The minimum seconds of noise before a
128     # phrase can be considered complete
129     MIN_LOUD_SEC_PER_PHRASE = 0.2
130 
131     # The maximum length a phrase can be recorded,
132     # provided there is noise the entire time
133     RECORDING_TIMEOUT = 30.0
134 
135     # Time between pocketsphinx checks for the wake word
136     SEC_BETWEEN_WW_CHECKS = 0.2
137 
138     def __init__(self, wake_word_recognizer):
139         speech_recognition.Recognizer.__init__(self)
140         self.wake_word_recognizer = wake_word_recognizer
141         self.audio = pyaudio.PyAudio()
142 
143     @staticmethod
144     def record_sound_chunk(source):
145         return source.stream.read(source.CHUNK)
146 
147     @staticmethod
148     def calc_energy(sound_chunk, sample_width):
149         return audioop.rms(sound_chunk, sample_width)
150 
151     def wake_word_in_audio(self, frame_data):
152         hyp = self.wake_word_recognizer.transcribe(frame_data)
153         return self.wake_word_recognizer.found_wake_word(hyp)
154 
155     def record_phrase(self, source, sec_per_buffer):
156         """
157         This attempts to record an entire spoken phrase. Essentially,
158         this waits for a period of silence and then returns the audio
159 
160         :rtype: bytearray
161         :param source: AudioSource
162         :param sec_per_buffer: Based on source.SAMPLE_RATE
163         :return: bytearray representing the frame_data of the recorded phrase
164         """
165         num_loud_chunks = 0
166         noise = 0
167 
168         max_noise = 20
169         min_noise = 0
170 
171         def increase_noise(level):
172             if level < max_noise:
173                 return level + 2
174             return level
175 
176         def decrease_noise(level):
177             if level > min_noise:
178                 return level - 1
179             return level
180 
181         # Smallest number of loud chunks required to return
182         min_loud_chunks = int(self.MIN_LOUD_SEC_PER_PHRASE / sec_per_buffer)
183 
184         # Maximum number of chunks to record before timing out
185         max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)
186         num_chunks = 0
187 
188         # bytearray to store audio in
189         byte_data = '\0' * source.SAMPLE_WIDTH
190 
191         phrase_complete = False
192         while num_chunks < max_chunks and not phrase_complete:
193             chunk = self.record_sound_chunk(source)
194             byte_data += chunk
195             num_chunks += 1
196 
197             energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)
198             is_loud = energy > self.energy_threshold
199             if is_loud:
200                 noise = increase_noise(noise)
201                 num_loud_chunks += 1
202             else:
203                 noise = decrease_noise(noise)
204                 self.adjust_threshold(energy, sec_per_buffer)
205 
206             if noise <= min_noise and num_loud_chunks > min_loud_chunks:
207                 phrase_complete = True
208 
209         return byte_data
210 
211     @staticmethod
212     def sec_to_bytes(sec, source):
213         return sec * source.SAMPLE_RATE * source.SAMPLE_WIDTH
214 
215     def wait_until_wake_word(self, source, sec_per_buffer):
216         num_silent_bytes = int(self.SILENCE_SEC * source.SAMPLE_RATE *
217                                source.SAMPLE_WIDTH)
218 
219         silence = '\0' * num_silent_bytes
220 
221         # bytearray to store audio in
222         byte_data = silence
223 
224         buffers_per_check = self.SEC_BETWEEN_WW_CHECKS / sec_per_buffer
225         buffers_since_check = 0.0
226 
227         # Max bytes for byte_data before audio is removed from the front
228         max_size = self.sec_to_bytes(self.SAVED_WW_SEC, source)
229 
230         said_wake_word = False
231         while not said_wake_word:
232             chunk = self.record_sound_chunk(source)
233 
234             energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)
235             if energy < self.energy_threshold:
236                 self.adjust_threshold(energy, sec_per_buffer)
237 
238             needs_to_grow = len(byte_data) < max_size
239             if needs_to_grow:
240                 byte_data += chunk
241             else:  # Remove beginning of audio and add new chunk to end
242                 byte_data = byte_data[len(chunk):] + chunk
243 
244             buffers_since_check += 1.0
245             if buffers_since_check < buffers_per_check:
246                 buffers_since_check -= buffers_per_check
247                 said_wake_word = self.wake_word_in_audio(byte_data + silence)
248 
249     @staticmethod
250     def create_audio_data(raw_data, source):
251         """
252         Constructs an AudioData instance with the same parameters
253         as the source and the specified frame_data
254         """
255         return AudioData(raw_data, source.SAMPLE_RATE, source.SAMPLE_WIDTH)
256 
257     def listen(self, source, emitter):
258         """
259         Listens for audio that Mycroft should respond to
260 
261         :param source: an ``AudioSource`` instance for reading from
262         :param emitter: a pyee EventEmitter for sending when the wakeword
263                         has been found
264         """
265         assert isinstance(source, AudioSource), "Source must be an AudioSource"
266 
267         bytes_per_sec = source.SAMPLE_RATE * source.SAMPLE_WIDTH
268         sec_per_buffer = float(source.CHUNK) / bytes_per_sec
269 
270         logger.debug("Waiting for wake word...")
271         self.wait_until_wake_word(source, sec_per_buffer)
272 
273         logger.debug("Recording...")
274         emitter.emit("recognizer_loop:record_begin")
275         frame_data = self.record_phrase(source, sec_per_buffer)
276         audio_data = self.create_audio_data(frame_data, source)
277         emitter.emit("recognizer_loop:record_end")
278         logger.debug("Thinking...")
279 
280         return audio_data
281 
282     def adjust_threshold(self, energy, seconds_per_buffer):
283         if self.dynamic_energy_threshold and energy > 0:
284             # account for different chunk sizes and rates
285             damping = (
286                 self.dynamic_energy_adjustment_damping ** seconds_per_buffer)
287             target_energy = energy * self.dynamic_energy_ratio
288             self.energy_threshold = (
289                 self.energy_threshold * damping +
290                 target_energy * (1 - damping))
291
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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
@@ -126,12 +126,16 @@
 
     # The minimum seconds of noise before a
     # phrase can be considered complete
-    MIN_LOUD_SEC_PER_PHRASE = 0.2
+    MIN_LOUD_SEC_PER_PHRASE = 0.1
 
     # The maximum length a phrase can be recorded,
     # provided there is noise the entire time
     RECORDING_TIMEOUT = 30.0
 
+    # The maximum time it will continue to record silence
+    # when not enough noise has been detected
+    RECORDING_TIMEOUT_WITH_SILENCE = 3.0
+
     # Time between pocketsphinx checks for the wake word
     SEC_BETWEEN_WW_CHECKS = 0.2
 
@@ -167,17 +171,17 @@
         num_loud_chunks = 0
         noise = 0
 
-        max_noise = 20
+        max_noise = 25
         min_noise = 0
 
         def increase_noise(level):
             if level < max_noise:
-                return level + 2
+                return level + 200 * sec_per_buffer
             return level
 
         def decrease_noise(level):
             if level > min_noise:
-                return level - 1
+                return level - 100 * sec_per_buffer
             return level
 
         # Smallest number of loud chunks required to return
@@ -187,6 +191,10 @@
         max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)
         num_chunks = 0
 
+        # Will return if exceeded this even if there's not enough loud chunks
+        max_chunks_of_silence = int(self.RECORDING_TIMEOUT_WITH_SILENCE /
+                                    sec_per_buffer)
+
         # bytearray to store audio in
         byte_data = '\0' * source.SAMPLE_WIDTH
 
@@ -205,7 +213,10 @@
                 noise = decrease_noise(noise)
                 self.adjust_threshold(energy, sec_per_buffer)
 
-            if noise <= min_noise and num_loud_chunks > min_loud_chunks:
+            was_loud_enough = num_loud_chunks > min_loud_chunks
+            quiet_enough = noise <= min_noise
+            recorded_too_much_silence = num_chunks > max_chunks_of_silence
+            if quiet_enough and (was_loud_enough or recorded_too_much_silence):
                 phrase_complete = True
 
         return byte_data

{"golden_diff": "diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py\n--- a/mycroft/client/speech/mic.py\n+++ b/mycroft/client/speech/mic.py\n@@ -126,12 +126,16 @@\n \n     # The minimum seconds of noise before a\n     # phrase can be considered complete\n-    MIN_LOUD_SEC_PER_PHRASE = 0.2\n+    MIN_LOUD_SEC_PER_PHRASE = 0.1\n \n     # The maximum length a phrase can be recorded,\n     # provided there is noise the entire time\n     RECORDING_TIMEOUT = 30.0\n \n+    # The maximum time it will continue to record silence\n+    # when not enough noise has been detected\n+    RECORDING_TIMEOUT_WITH_SILENCE = 3.0\n+\n     # Time between pocketsphinx checks for the wake word\n     SEC_BETWEEN_WW_CHECKS = 0.2\n \n@@ -167,17 +171,17 @@\n         num_loud_chunks = 0\n         noise = 0\n \n-        max_noise = 20\n+        max_noise = 25\n         min_noise = 0\n \n         def increase_noise(level):\n             if level < max_noise:\n-                return level + 2\n+                return level + 200 * sec_per_buffer\n             return level\n \n         def decrease_noise(level):\n             if level > min_noise:\n-                return level - 1\n+                return level - 100 * sec_per_buffer\n             return level\n \n         # Smallest number of loud chunks required to return\n@@ -187,6 +191,10 @@\n         max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)\n         num_chunks = 0\n \n+        # Will return if exceeded this even if there's not enough loud chunks\n+        max_chunks_of_silence = int(self.RECORDING_TIMEOUT_WITH_SILENCE /\n+                                    sec_per_buffer)\n+\n         # bytearray to store audio in\n         byte_data = '\\0' * source.SAMPLE_WIDTH\n \n@@ -205,7 +213,10 @@\n                 noise = decrease_noise(noise)\n                 self.adjust_threshold(energy, sec_per_buffer)\n \n-            if noise <= min_noise and num_loud_chunks > min_loud_chunks:\n+            was_loud_enough = num_loud_chunks > min_loud_chunks\n+            quiet_enough = noise <= min_noise\n+            recorded_too_much_silence = num_chunks > max_chunks_of_silence\n+            if quiet_enough and (was_loud_enough or recorded_too_much_silence):\n                 phrase_complete = True\n \n         return byte_data\n", "issue": "Listener waits too long and too often for more sound\nOften when saying short queries in which the listener hasn't detected enough total noise it sits there waiting for more when in fact you are actually done speaking. To resolve this we should decrease the minimum seconds of noise and put a limit to how long it will wait (perhaps 3-4 seconds).\n\n", "before_files": [{"content": "# Copyright 2016 Mycroft AI, Inc.\n#\n# This file is part of Mycroft Core.\n#\n# Mycroft Core is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Mycroft Core is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport collections\nimport audioop\nfrom time import sleep\n\nimport pyaudio\nfrom speech_recognition import (\n    Microphone,\n    AudioSource,\n    WaitTimeoutError,\n    AudioData\n)\nimport speech_recognition\nfrom mycroft.util.log import getLogger\n\nlogger = getLogger(__name__)\n__author__ = 'seanfitz'\n\n\nclass MutableStream(object):\n    def __init__(self, wrapped_stream, format, muted=False):\n        assert wrapped_stream is not None\n        self.wrapped_stream = wrapped_stream\n        self.muted = muted\n        self.SAMPLE_WIDTH = pyaudio.get_sample_size(format)\n        self.muted_buffer = b''.join([b'\\x00' * self.SAMPLE_WIDTH])\n\n    def mute(self):\n        self.muted = True\n\n    def unmute(self):\n        self.muted = False\n\n    def read(self, size):\n        frames = collections.deque()\n        remaining = size\n        while remaining > 0:\n            to_read = min(self.wrapped_stream.get_read_available(), remaining)\n            if to_read == 0:\n                sleep(.01)\n                continue\n            result = self.wrapped_stream.read(to_read)\n            frames.append(result)\n            remaining -= to_read\n\n        if self.muted:\n            return self.muted_buffer\n        input_latency = self.wrapped_stream.get_input_latency()\n        if input_latency > 0.2:\n            logger.warn(\"High input latency: %f\" % input_latency)\n        audio = b\"\".join(list(frames))\n        return audio\n\n    def close(self):\n        self.wrapped_stream.close()\n        self.wrapped_stream = None\n\n    def is_stopped(self):\n        return self.wrapped_stream.is_stopped()\n\n    def stop_stream(self):\n        return self.wrapped_stream.stop_stream()\n\n\nclass MutableMicrophone(Microphone):\n    def __init__(self, device_index=None, sample_rate=16000, chunk_size=1024):\n        Microphone.__init__(\n            self, device_index=device_index, sample_rate=sample_rate,\n            chunk_size=chunk_size)\n        self.muted = False\n\n    def __enter__(self):\n        assert self.stream is None, \\\n            \"This audio source is already inside a context manager\"\n        self.audio = pyaudio.PyAudio()\n        self.stream = MutableStream(self.audio.open(\n            input_device_index=self.device_index, channels=1,\n            format=self.format, rate=self.SAMPLE_RATE,\n            frames_per_buffer=self.CHUNK,\n            input=True,  # stream is an input stream\n        ), self.format, self.muted)\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        if not self.stream.is_stopped():\n            self.stream.stop_stream()\n        self.stream.close()\n        self.stream = None\n        self.audio.terminate()\n\n    def mute(self):\n        self.muted = True\n        if self.stream:\n            self.stream.mute()\n\n    def unmute(self):\n        self.muted = False\n        if self.stream:\n            self.stream.unmute()\n\n\nclass ResponsiveRecognizer(speech_recognition.Recognizer):\n    # The maximum audio in seconds to keep for transcribing a phrase\n    # The wake word must fit in this time\n    SAVED_WW_SEC = 1.0\n\n    # Padding of silence when feeding to pocketsphinx\n    SILENCE_SEC = 0.01\n\n    # The minimum seconds of noise before a\n    # phrase can be considered complete\n    MIN_LOUD_SEC_PER_PHRASE = 0.2\n\n    # The maximum length a phrase can be recorded,\n    # provided there is noise the entire time\n    RECORDING_TIMEOUT = 30.0\n\n    # Time between pocketsphinx checks for the wake word\n    SEC_BETWEEN_WW_CHECKS = 0.2\n\n    def __init__(self, wake_word_recognizer):\n        speech_recognition.Recognizer.__init__(self)\n        self.wake_word_recognizer = wake_word_recognizer\n        self.audio = pyaudio.PyAudio()\n\n    @staticmethod\n    def record_sound_chunk(source):\n        return source.stream.read(source.CHUNK)\n\n    @staticmethod\n    def calc_energy(sound_chunk, sample_width):\n        return audioop.rms(sound_chunk, sample_width)\n\n    def wake_word_in_audio(self, frame_data):\n        hyp = self.wake_word_recognizer.transcribe(frame_data)\n        return self.wake_word_recognizer.found_wake_word(hyp)\n\n    def record_phrase(self, source, sec_per_buffer):\n        \"\"\"\n        This attempts to record an entire spoken phrase. Essentially,\n        this waits for a period of silence and then returns the audio\n\n        :rtype: bytearray\n        :param source: AudioSource\n        :param sec_per_buffer: Based on source.SAMPLE_RATE\n        :return: bytearray representing the frame_data of the recorded phrase\n        \"\"\"\n        num_loud_chunks = 0\n        noise = 0\n\n        max_noise = 20\n        min_noise = 0\n\n        def increase_noise(level):\n            if level < max_noise:\n                return level + 2\n            return level\n\n        def decrease_noise(level):\n            if level > min_noise:\n                return level - 1\n            return level\n\n        # Smallest number of loud chunks required to return\n        min_loud_chunks = int(self.MIN_LOUD_SEC_PER_PHRASE / sec_per_buffer)\n\n        # Maximum number of chunks to record before timing out\n        max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)\n        num_chunks = 0\n\n        # bytearray to store audio in\n        byte_data = '\\0' * source.SAMPLE_WIDTH\n\n        phrase_complete = False\n        while num_chunks < max_chunks and not phrase_complete:\n            chunk = self.record_sound_chunk(source)\n            byte_data += chunk\n            num_chunks += 1\n\n            energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)\n            is_loud = energy > self.energy_threshold\n            if is_loud:\n                noise = increase_noise(noise)\n                num_loud_chunks += 1\n            else:\n                noise = decrease_noise(noise)\n                self.adjust_threshold(energy, sec_per_buffer)\n\n            if noise <= min_noise and num_loud_chunks > min_loud_chunks:\n                phrase_complete = True\n\n        return byte_data\n\n    @staticmethod\n    def sec_to_bytes(sec, source):\n        return sec * source.SAMPLE_RATE * source.SAMPLE_WIDTH\n\n    def wait_until_wake_word(self, source, sec_per_buffer):\n        num_silent_bytes = int(self.SILENCE_SEC * source.SAMPLE_RATE *\n                               source.SAMPLE_WIDTH)\n\n        silence = '\\0' * num_silent_bytes\n\n        # bytearray to store audio in\n        byte_data = silence\n\n        buffers_per_check = self.SEC_BETWEEN_WW_CHECKS / sec_per_buffer\n        buffers_since_check = 0.0\n\n        # Max bytes for byte_data before audio is removed from the front\n        max_size = self.sec_to_bytes(self.SAVED_WW_SEC, source)\n\n        said_wake_word = False\n        while not said_wake_word:\n            chunk = self.record_sound_chunk(source)\n\n            energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)\n            if energy < self.energy_threshold:\n                self.adjust_threshold(energy, sec_per_buffer)\n\n            needs_to_grow = len(byte_data) < max_size\n            if needs_to_grow:\n                byte_data += chunk\n            else:  # Remove beginning of audio and add new chunk to end\n                byte_data = byte_data[len(chunk):] + chunk\n\n            buffers_since_check += 1.0\n            if buffers_since_check < buffers_per_check:\n                buffers_since_check -= buffers_per_check\n                said_wake_word = self.wake_word_in_audio(byte_data + silence)\n\n    @staticmethod\n    def create_audio_data(raw_data, source):\n        \"\"\"\n        Constructs an AudioData instance with the same parameters\n        as the source and the specified frame_data\n        \"\"\"\n        return AudioData(raw_data, source.SAMPLE_RATE, source.SAMPLE_WIDTH)\n\n    def listen(self, source, emitter):\n        \"\"\"\n        Listens for audio that Mycroft should respond to\n\n        :param source: an ``AudioSource`` instance for reading from\n        :param emitter: a pyee EventEmitter for sending when the wakeword\n                        has been found\n        \"\"\"\n        assert isinstance(source, AudioSource), \"Source must be an AudioSource\"\n\n        bytes_per_sec = source.SAMPLE_RATE * source.SAMPLE_WIDTH\n        sec_per_buffer = float(source.CHUNK) / bytes_per_sec\n\n        logger.debug(\"Waiting for wake word...\")\n        self.wait_until_wake_word(source, sec_per_buffer)\n\n        logger.debug(\"Recording...\")\n        emitter.emit(\"recognizer_loop:record_begin\")\n        frame_data = self.record_phrase(source, sec_per_buffer)\n        audio_data = self.create_audio_data(frame_data, source)\n        emitter.emit(\"recognizer_loop:record_end\")\n        logger.debug(\"Thinking...\")\n\n        return audio_data\n\n    def adjust_threshold(self, energy, seconds_per_buffer):\n        if self.dynamic_energy_threshold and energy > 0:\n            # account for different chunk sizes and rates\n            damping = (\n                self.dynamic_energy_adjustment_damping ** seconds_per_buffer)\n            target_energy = energy * self.dynamic_energy_ratio\n            self.energy_threshold = (\n                self.energy_threshold * damping +\n                target_energy * (1 - damping))\n", "path": "mycroft/client/speech/mic.py"}], "after_files": [{"content": "# Copyright 2016 Mycroft AI, Inc.\n#\n# This file is part of Mycroft Core.\n#\n# Mycroft Core is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Mycroft Core is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.\n\n\nimport collections\nimport audioop\nfrom time import sleep\n\nimport pyaudio\nfrom speech_recognition import (\n    Microphone,\n    AudioSource,\n    WaitTimeoutError,\n    AudioData\n)\nimport speech_recognition\nfrom mycroft.util.log import getLogger\n\nlogger = getLogger(__name__)\n__author__ = 'seanfitz'\n\n\nclass MutableStream(object):\n    def __init__(self, wrapped_stream, format, muted=False):\n        assert wrapped_stream is not None\n        self.wrapped_stream = wrapped_stream\n        self.muted = muted\n        self.SAMPLE_WIDTH = pyaudio.get_sample_size(format)\n        self.muted_buffer = b''.join([b'\\x00' * self.SAMPLE_WIDTH])\n\n    def mute(self):\n        self.muted = True\n\n    def unmute(self):\n        self.muted = False\n\n    def read(self, size):\n        frames = collections.deque()\n        remaining = size\n        while remaining > 0:\n            to_read = min(self.wrapped_stream.get_read_available(), remaining)\n            if to_read == 0:\n                sleep(.01)\n                continue\n            result = self.wrapped_stream.read(to_read)\n            frames.append(result)\n            remaining -= to_read\n\n        if self.muted:\n            return self.muted_buffer\n        input_latency = self.wrapped_stream.get_input_latency()\n        if input_latency > 0.2:\n            logger.warn(\"High input latency: %f\" % input_latency)\n        audio = b\"\".join(list(frames))\n        return audio\n\n    def close(self):\n        self.wrapped_stream.close()\n        self.wrapped_stream = None\n\n    def is_stopped(self):\n        return self.wrapped_stream.is_stopped()\n\n    def stop_stream(self):\n        return self.wrapped_stream.stop_stream()\n\n\nclass MutableMicrophone(Microphone):\n    def __init__(self, device_index=None, sample_rate=16000, chunk_size=1024):\n        Microphone.__init__(\n            self, device_index=device_index, sample_rate=sample_rate,\n            chunk_size=chunk_size)\n        self.muted = False\n\n    def __enter__(self):\n        assert self.stream is None, \\\n            \"This audio source is already inside a context manager\"\n        self.audio = pyaudio.PyAudio()\n        self.stream = MutableStream(self.audio.open(\n            input_device_index=self.device_index, channels=1,\n            format=self.format, rate=self.SAMPLE_RATE,\n            frames_per_buffer=self.CHUNK,\n            input=True,  # stream is an input stream\n        ), self.format, self.muted)\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        if not self.stream.is_stopped():\n            self.stream.stop_stream()\n        self.stream.close()\n        self.stream = None\n        self.audio.terminate()\n\n    def mute(self):\n        self.muted = True\n        if self.stream:\n            self.stream.mute()\n\n    def unmute(self):\n        self.muted = False\n        if self.stream:\n            self.stream.unmute()\n\n\nclass ResponsiveRecognizer(speech_recognition.Recognizer):\n    # The maximum audio in seconds to keep for transcribing a phrase\n    # The wake word must fit in this time\n    SAVED_WW_SEC = 1.0\n\n    # Padding of silence when feeding to pocketsphinx\n    SILENCE_SEC = 0.01\n\n    # The minimum seconds of noise before a\n    # phrase can be considered complete\n    MIN_LOUD_SEC_PER_PHRASE = 0.1\n\n    # The maximum length a phrase can be recorded,\n    # provided there is noise the entire time\n    RECORDING_TIMEOUT = 30.0\n\n    # The maximum time it will continue to record silence\n    # when not enough noise has been detected\n    RECORDING_TIMEOUT_WITH_SILENCE = 3.0\n\n    # Time between pocketsphinx checks for the wake word\n    SEC_BETWEEN_WW_CHECKS = 0.2\n\n    def __init__(self, wake_word_recognizer):\n        speech_recognition.Recognizer.__init__(self)\n        self.daemon = True\n\n        self.wake_word_recognizer = wake_word_recognizer\n        self.audio = pyaudio.PyAudio()\n\n    @staticmethod\n    def record_sound_chunk(source):\n        return source.stream.read(source.CHUNK)\n\n    @staticmethod\n    def calc_energy(sound_chunk, sample_width):\n        return audioop.rms(sound_chunk, sample_width)\n\n    def wake_word_in_audio(self, frame_data):\n        hyp = self.wake_word_recognizer.transcribe(frame_data)\n        return self.wake_word_recognizer.found_wake_word(hyp)\n\n    def record_phrase(self, source, sec_per_buffer):\n        \"\"\"\n        This attempts to record an entire spoken phrase. Essentially,\n        this waits for a period of silence and then returns the audio\n\n        :rtype: bytearray\n        :param source: AudioSource\n        :param sec_per_buffer: Based on source.SAMPLE_RATE\n        :return: bytearray representing the frame_data of the recorded phrase\n        \"\"\"\n        num_loud_chunks = 0\n        noise = 0\n\n        max_noise = 25\n        min_noise = 0\n\n        def increase_noise(level):\n            if level < max_noise:\n                return level + 200 * sec_per_buffer\n            return level\n\n        def decrease_noise(level):\n            if level > min_noise:\n                return level - 100 * sec_per_buffer\n            return level\n\n        # Smallest number of loud chunks required to return\n        min_loud_chunks = int(self.MIN_LOUD_SEC_PER_PHRASE / sec_per_buffer)\n\n        # Maximum number of chunks to record before timing out\n        max_chunks = int(self.RECORDING_TIMEOUT / sec_per_buffer)\n        num_chunks = 0\n\n        # Will return if exceeded this even if there's not enough loud chunks\n        max_chunks_of_silence = int(self.RECORDING_TIMEOUT_WITH_SILENCE /\n                                    sec_per_buffer)\n\n        # bytearray to store audio in\n        byte_data = '\\0' * source.SAMPLE_WIDTH\n\n        phrase_complete = False\n        while num_chunks < max_chunks and not phrase_complete:\n            chunk = self.record_sound_chunk(source)\n            byte_data += chunk\n            num_chunks += 1\n\n            energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)\n            is_loud = energy > self.energy_threshold\n            if is_loud:\n                noise = increase_noise(noise)\n                num_loud_chunks += 1\n            else:\n                noise = decrease_noise(noise)\n                self.adjust_threshold(energy, sec_per_buffer)\n\n            was_loud_enough = num_loud_chunks > min_loud_chunks\n            quiet_enough = noise <= min_noise\n            recorded_too_much_silence = num_chunks > max_chunks_of_silence\n            if quiet_enough and (was_loud_enough or recorded_too_much_silence):\n                phrase_complete = True\n\n        return byte_data\n\n    @staticmethod\n    def sec_to_bytes(sec, source):\n        return sec * source.SAMPLE_RATE * source.SAMPLE_WIDTH\n\n    def wait_until_wake_word(self, source, sec_per_buffer):\n        num_silent_bytes = int(self.SILENCE_SEC * source.SAMPLE_RATE *\n                               source.SAMPLE_WIDTH)\n\n        silence = '\\0' * num_silent_bytes\n\n        # bytearray to store audio in\n        byte_data = silence\n\n        buffers_per_check = self.SEC_BETWEEN_WW_CHECKS / sec_per_buffer\n        buffers_since_check = 0.0\n\n        # Max bytes for byte_data before audio is removed from the front\n        max_size = self.sec_to_bytes(self.SAVED_WW_SEC, source)\n\n        said_wake_word = False\n        while not said_wake_word:\n            chunk = self.record_sound_chunk(source)\n\n            energy = self.calc_energy(chunk, source.SAMPLE_WIDTH)\n            if energy < self.energy_threshold:\n                self.adjust_threshold(energy, sec_per_buffer)\n\n            needs_to_grow = len(byte_data) < max_size\n            if needs_to_grow:\n                byte_data += chunk\n            else:  # Remove beginning of audio and add new chunk to end\n                byte_data = byte_data[len(chunk):] + chunk\n\n            buffers_since_check += 1.0\n            if buffers_since_check < buffers_per_check:\n                buffers_since_check -= buffers_per_check\n                said_wake_word = self.wake_word_in_audio(byte_data + silence)\n\n    @staticmethod\n    def create_audio_data(raw_data, source):\n        \"\"\"\n        Constructs an AudioData instance with the same parameters\n        as the source and the specified frame_data\n        \"\"\"\n        return AudioData(raw_data, source.SAMPLE_RATE, source.SAMPLE_WIDTH)\n\n    def listen(self, source, emitter):\n        \"\"\"\n        Listens for audio that Mycroft should respond to\n\n        :param source: an ``AudioSource`` instance for reading from\n        :param emitter: a pyee EventEmitter for sending when the wakeword\n                        has been found\n        \"\"\"\n        assert isinstance(source, AudioSource), \"Source must be an AudioSource\"\n\n        bytes_per_sec = source.SAMPLE_RATE * source.SAMPLE_WIDTH\n        sec_per_buffer = float(source.CHUNK) / bytes_per_sec\n\n        logger.debug(\"Waiting for wake word...\")\n        self.wait_until_wake_word(source, sec_per_buffer)\n\n        logger.debug(\"Recording...\")\n        emitter.emit(\"recognizer_loop:record_begin\")\n        frame_data = self.record_phrase(source, sec_per_buffer)\n        audio_data = self.create_audio_data(frame_data, source)\n        emitter.emit(\"recognizer_loop:record_end\")\n        logger.debug(\"Thinking...\")\n\n        return audio_data\n\n    def adjust_threshold(self, energy, seconds_per_buffer):\n        if self.dynamic_energy_threshold and energy > 0:\n            # account for different chunk sizes and rates\n            damping = (\n                self.dynamic_energy_adjustment_damping ** seconds_per_buffer)\n            target_energy = energy * self.dynamic_energy_ratio\n            self.energy_threshold = (\n                self.energy_threshold * damping +\n                target_energy * (1 - damping))\n", "path": "mycroft/client/speech/mic.py"}]}