files.new_contents: # Copyright 2016 Mycroft AI, Inc.
  #
  # This file is part of Mycroft Core.
  #
  # Mycroft Core is free software: you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation, either version 3 of the License, or
  # (at your option) any later version.
  #
  # Mycroft Core is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU General Public License for more details.
  #
  # You should have received a copy of the GNU General Public License
  # along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
  
  
  import time
  from Queue import Queue
  from threading import Thread
  
  import speech_recognition as sr
  from pyee import EventEmitter
  from requests import HTTPError
  from requests.exceptions import ConnectionError
  
  import mycroft.dialog
  from mycroft.client.speech.local_recognizer import LocalRecognizer
  from mycroft.client.speech.mic import MutableMicrophone, ResponsiveRecognizer
  from mycroft.configuration import ConfigurationManager
  from mycroft.messagebus.message import Message
  from mycroft.metrics import MetricsAggregator
  from mycroft.session import SessionManager
  from mycroft.stt import STTFactory
  from mycroft.util import connected
  from mycroft.util.log import getLogger
  
  LOG = getLogger(__name__)
  
  
  class AudioProducer(Thread):
      """
      AudioProducer
      given a mic and a recognizer implementation, continuously listens to the
      mic for potential speech chunks and pushes them onto the queue.
      """
  
      def __init__(self, state, queue, mic, recognizer, emitter):
          super(AudioProducer, self).__init__()
          self.daemon = True
          self.state = state
          self.queue = queue
          self.mic = mic
          self.recognizer = recognizer
          self.emitter = emitter
  
      def run(self):
          with self.mic as source:
              self.recognizer.adjust_for_ambient_noise(source)
              while self.state.running:
                  try:
                      audio = self.recognizer.listen(source, self.emitter)
                      self.queue.put(audio)
                  except IOError, ex:
                      # NOTE: Audio stack on raspi is slightly different, throws
                      # IOError every other listen, almost like it can't handle
                      # buffering audio between listen loops.
                      # The internet was not helpful.
                      # http://stackoverflow.com/questions/10733903/pyaudio-input-overflowed
                      self.emitter.emit("recognizer_loop:ioerror", ex)
  
      def stop(self):
          self.state.running = False
          self.recognizer.stop()
  
  
  class AudioConsumer(Thread):
      """
      AudioConsumer
      Consumes AudioData chunks off the queue
      """
  
      # In seconds, the minimum audio size to be sent to remote STT
      MIN_AUDIO_SIZE = 0.5
  
      def __init__(self, state, queue, emitter, stt,
                   wakeup_recognizer, mycroft_recognizer):
          super(AudioConsumer, self).__init__()
          self.daemon = True
          self.queue = queue
          self.state = state
          self.emitter = emitter
          self.stt = stt
          self.wakeup_recognizer = wakeup_recognizer
          self.mycroft_recognizer = mycroft_recognizer
          self.metrics = MetricsAggregator()
  
      def run(self):
          while self.state.running:
              self.read()
  
      def read(self):
          audio = self.queue.get()
  
          if self.state.sleeping:
              self.wake_up(audio)
          elif audio is not None:
              self.process(audio)
  
      # TODO: Localization
      def wake_up(self, audio):
          if self.wakeup_recognizer.is_recognized(audio.frame_data,
                                                  self.metrics):
              SessionManager.touch()
              self.state.sleeping = False
              self.__speak(mycroft.dialog.get("i am awake", self.stt.lang))
              self.metrics.increment("mycroft.wakeup")
  
      @staticmethod
      def _audio_length(audio):
          return float(len(audio.frame_data)) / (
              audio.sample_rate * audio.sample_width)
  
      # TODO: Localization
      def process(self, audio):
          SessionManager.touch()
          payload = {
              'utterance': self.mycroft_recognizer.key_phrase,
              'session': SessionManager.get().session_id
  
  [... the rest is omitted ...]
files.new_path: mycroft/client/speech/listener.py
files.old_contents: # Copyright 2016 Mycroft AI, Inc.
  #
  # This file is part of Mycroft Core.
  #
  # Mycroft Core is free software: you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation, either version 3 of the License, or
  # (at your option) any later version.
  #
  # Mycroft Core is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU General Public License for more details.
  #
  # You should have received a copy of the GNU General Public License
  # along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
  
  
  import time
  from Queue import Queue
  from threading import Thread
  
  import speech_recognition as sr
  from pyee import EventEmitter
  from requests import HTTPError
  from requests.exceptions import ConnectionError
  
  import mycroft.dialog
  from mycroft.client.speech.local_recognizer import LocalRecognizer
  from mycroft.client.speech.mic import MutableMicrophone, ResponsiveRecognizer
  from mycroft.configuration import ConfigurationManager
  from mycroft.messagebus.message import Message
  from mycroft.metrics import MetricsAggregator
  from mycroft.session import SessionManager
  from mycroft.stt import STTFactory
  from mycroft.util import connected
  from mycroft.util.log import getLogger
  
  LOG = getLogger(__name__)
  
  
  class AudioProducer(Thread):
      """
      AudioProducer
      given a mic and a recognizer implementation, continuously listens to the
      mic for potential speech chunks and pushes them onto the queue.
      """
  
      def __init__(self, state, queue, mic, recognizer, emitter):
          super(AudioProducer, self).__init__()
          self.daemon = True
          self.state = state
          self.queue = queue
          self.mic = mic
          self.recognizer = recognizer
          self.emitter = emitter
  
      def run(self):
          with self.mic as source:
              self.recognizer.adjust_for_ambient_noise(source)
              while self.state.running:
                  try:
                      audio = self.recognizer.listen(source, self.emitter)
                      self.queue.put(audio)
                  except IOError, ex:
                      # NOTE: Audio stack on raspi is slightly different, throws
                      # IOError every other listen, almost like it can't handle
                      # buffering audio between listen loops.
                      # The internet was not helpful.
                      # http://stackoverflow.com/questions/10733903/pyaudio-input-overflowed
                      self.emitter.emit("recognizer_loop:ioerror", ex)
  
  
  class AudioConsumer(Thread):
      """
      AudioConsumer
      Consumes AudioData chunks off the queue
      """
  
      # In seconds, the minimum audio size to be sent to remote STT
      MIN_AUDIO_SIZE = 0.5
  
      def __init__(self, state, queue, emitter, stt,
                   wakeup_recognizer, mycroft_recognizer):
          super(AudioConsumer, self).__init__()
          self.daemon = True
          self.queue = queue
          self.state = state
          self.emitter = emitter
          self.stt = stt
          self.wakeup_recognizer = wakeup_recognizer
          self.mycroft_recognizer = mycroft_recognizer
          self.metrics = MetricsAggregator()
  
      def run(self):
          while self.state.running:
              self.read()
  
      def read(self):
          audio = self.queue.get()
  
          if self.state.sleeping:
              self.wake_up(audio)
          else:
              self.process(audio)
  
      # TODO: Localization
      def wake_up(self, audio):
          if self.wakeup_recognizer.is_recognized(audio.frame_data,
                                                  self.metrics):
              SessionManager.touch()
              self.state.sleeping = False
              self.__speak(mycroft.dialog.get("i am awake", self.stt.lang))
              self.metrics.increment("mycroft.wakeup")
  
      @staticmethod
      def _audio_length(audio):
          return float(len(audio.frame_data)) / (
              audio.sample_rate * audio.sample_width)
  
      # TODO: Localization
      def process(self, audio):
          SessionManager.touch()
          payload = {
              'utterance': self.mycroft_recognizer.key_phrase,
              'session': SessionManager.get().session_id,
          }
          self.emitter.emit("recognizer_loop:wakeword", payload)
  
          if self._
  
  [... the rest is omitted ...]
files.old_path: mycroft/client/speech/listener.py
files.new_contents: """ Copyright 2016 Mycroft AI, Inc.
  
   This file is part of Mycroft Core.
  
   Mycroft Core is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
  
   Mycroft Core is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
  """
  
  import collections
  import datetime
  import os
  from time import sleep
  import audioop
  
  import pyaudio
  import speech_recognition
  from speech_recognition import (
      Microphone,
      AudioSource,
      AudioData
  )
  
  from mycroft.configuration import ConfigurationManager
  from mycroft.util import (
      check_for_signal,
      get_ipc_directory,
      resolve_resource_file,
      play_wav
  )
  from mycroft.util.log import getLogger
  
  config = ConfigurationManager.instance()
  listener_config = config.get('listener')
  logger = getLogger(__name__)
  __author__ = 'seanfitz'
  
  
  class MutableStream(object):
  
      def __init__(self, wrapped_stream, format, muted=False):
          assert wrapped_stream is not None
          self.wrapped_stream = wrapped_stream
          self.muted = muted
          self.SAMPLE_WIDTH = pyaudio.get_sample_size(format)
          self.muted_buffer = b''.join([b'\x00' * self.SAMPLE_WIDTH])
  
      def mute(self):
          self.muted = True
  
      def unmute(self):
          self.muted = False
  
      def read(self, size):
          frames = collections.deque()
          remaining = size
          while remaining > 0:
              to_read = min(self.wrapped_stream.get_read_available(), remaining)
              if to_read == 0:
                  sleep(.01)
                  continue
              result = self.wrapped_stream.read(to_read)
              frames.append(result)
              remaining -= to_read
  
          if self.muted:
              return self.muted_buffer
          input_latency = self.wrapped_stream.get_input_latency()
          if input_latency > 0.2:
              logger.warn("High input latency: %f" % input_latency)
          audio = b"".join(list(frames))
          return audio
  
      def close(self):
          self.wrapped_stream.close()
          self.wrapped_stream = None
  
      def is_stopped(self):
          return self.wrapped_stream.is_stopped()
  
      def stop_stream(self):
          return self.wrapped_stream.stop_stream()
  
  
  class MutableMicrophone(Microphone):
  
      def __init__(self, device_index=None, sample_rate=16000, chunk_size=1024):
          Microphone.__init__(
              self, device_index=device_index, sample_rate=sample_rate,
              chunk_size=chunk_size)
          self.muted = False
  
      def __enter__(self):
          assert self.stream is None, \
              "This audio source is already inside a context manager"
          self.audio = pyaudio.PyAudio()
          self.stream = MutableStream(self.audio.open(
              input_device_index=self.device_index, channels=1,
              format=self.format, rate=self.SAMPLE_RATE,
              frames_per_buffer=self.CHUNK,
              input=True,  # stream is an input stream
          ), self.format, self.muted)
          return self
  
      def __exit__(self, exc_type, exc_value, traceback):
          if not self.stream.is_stopped():
              self.stream.stop_stream()
          self.stream.close()
          self.stream = None
          self.audio.terminate()
  
      def mute(self):
          self.muted = True
          if self.stream:
              self.stream.mute()
  
      def unmute(self):
          self.muted = False
          if self.stream:
              self.stream.unmute()
  
  
  class ResponsiveRecognizer(speech_recognition.Recognizer):
      # The maximum audio in seconds to keep for transcribing a phrase
      # The wake word must fit in this time
      SAVED_WW_SEC = 1.0
  
      # Padding of silence when feeding to pocketsphinx
      SILENCE_SEC = 0.01
  
      # The minimum seconds of noise before a
      # phrase can be considered complete
      MIN_LOUD_SEC_PER_PHRASE = 0.5
  
      # The minimum seconds of silence required at the end
      # before a phrase
  
  [... the rest is omitted ...]
files.new_path: mycroft/client/speech/mic.py
files.old_contents: """ Copyright 2016 Mycroft AI, Inc.
  
   This file is part of Mycroft Core.
  
   Mycroft Core is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
  
   Mycroft Core is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with Mycroft Core.  If not, see <http://www.gnu.org/licenses/>.
  """
  
  import collections
  import datetime
  import os
  from time import sleep
  import audioop
  
  import pyaudio
  import speech_recognition
  from speech_recognition import (
      Microphone,
      AudioSource,
      AudioData
  )
  
  from mycroft.configuration import ConfigurationManager
  from mycroft.util import (
      check_for_signal,
      get_ipc_directory,
      resolve_resource_file,
      play_wav
  )
  from mycroft.util.log import getLogger
  
  config = ConfigurationManager.instance()
  listener_config = config.get('listener')
  logger = getLogger(__name__)
  __author__ = 'seanfitz'
  
  
  class MutableStream(object):
  
      def __init__(self, wrapped_stream, format, muted=False):
          assert wrapped_stream is not None
          self.wrapped_stream = wrapped_stream
          self.muted = muted
          self.SAMPLE_WIDTH = pyaudio.get_sample_size(format)
          self.muted_buffer = b''.join([b'\x00' * self.SAMPLE_WIDTH])
  
      def mute(self):
          self.muted = True
  
      def unmute(self):
          self.muted = False
  
      def read(self, size):
          frames = collections.deque()
          remaining = size
          while remaining > 0:
              to_read = min(self.wrapped_stream.get_read_available(), remaining)
              if to_read == 0:
                  sleep(.01)
                  continue
              result = self.wrapped_stream.read(to_read)
              frames.append(result)
              remaining -= to_read
  
          if self.muted:
              return self.muted_buffer
          input_latency = self.wrapped_stream.get_input_latency()
          if input_latency > 0.2:
              logger.warn("High input latency: %f" % input_latency)
          audio = b"".join(list(frames))
          return audio
  
      def close(self):
          self.wrapped_stream.close()
          self.wrapped_stream = None
  
      def is_stopped(self):
          return self.wrapped_stream.is_stopped()
  
      def stop_stream(self):
          return self.wrapped_stream.stop_stream()
  
  
  class MutableMicrophone(Microphone):
  
      def __init__(self, device_index=None, sample_rate=16000, chunk_size=1024):
          Microphone.__init__(
              self, device_index=device_index, sample_rate=sample_rate,
              chunk_size=chunk_size)
          self.muted = False
  
      def __enter__(self):
          assert self.stream is None, \
              "This audio source is already inside a context manager"
          self.audio = pyaudio.PyAudio()
          self.stream = MutableStream(self.audio.open(
              input_device_index=self.device_index, channels=1,
              format=self.format, rate=self.SAMPLE_RATE,
              frames_per_buffer=self.CHUNK,
              input=True,  # stream is an input stream
          ), self.format, self.muted)
          return self
  
      def __exit__(self, exc_type, exc_value, traceback):
          if not self.stream.is_stopped():
              self.stream.stop_stream()
          self.stream.close()
          self.stream = None
          self.audio.terminate()
  
      def mute(self):
          self.muted = True
          if self.stream:
              self.stream.mute()
  
      def unmute(self):
          self.muted = False
          if self.stream:
              self.stream.unmute()
  
  
  class ResponsiveRecognizer(speech_recognition.Recognizer):
      # The maximum audio in seconds to keep for transcribing a phrase
      # The wake word must fit in this time
      SAVED_WW_SEC = 1.0
  
      # Padding of silence when feeding to pocketsphinx
      SILENCE_SEC = 0.01
  
      # The minimum seconds of noise before a
      # phrase can be considered complete
      MIN_LOUD_SEC_PER_PHRASE = 0.5
  
      # The minimum seconds of silence required at the end
      # before a phrase
  
  [... the rest is omitted ...]
files.old_path: mycroft/client/speech/mic.py