# PAL
# Listener
# Thomas Elvey
# 0.2

import math, audioop, time, wave, os
from collections import deque
from pocketsphinx import *
import pyaudio

from VoiceDecoder import VoiceDecoder

class Listener():

    def __init__(self):        
        print "Listener Created"
        # INIT FUNCTIONS
        # self.setupMic()
        # self.listen()
        self.d = VoiceDecoder('/usr/share/pocketsphinx/model/hmm/en_US/hub4wsj_sc_8k',
                         '/home/pi/PAL/resources/PALActivate.dic',
                         '/home/pi/PAL/resources/PALActivate.lm',
                         '/home/pi/PAL/resources/PALActivateKeyphrase.list')

    def setupMic(self, samples = 50):
        # Setup microphone, background noise adjustments etc.
        
        print "Getting mic values..."
        p = pyaudio.PyAudio()
        stream = p.open(format = pyaudio.paInt16,
                                  channels = 1,
                                  rate = 16000,
                                  input = True,
                                  frames_per_buffer = 1024)
        values = [math.sqrt(abs(audioop.avg(stream.read(1024), 4)))
                  for x in range(samples)]
        values = sorted(values, reverse = True)
        r = sum(values[:int(samples * 0.2)]) / int(samples * 0.2)
        print "Finished, Average aduio noise is: ", r
        stream.close()
        p.terminate()

        if r < 3000:
            self.threshold = 3500
        else:
            self.threshold = r + 100

    def saveVoice(self, data, p):
        filename = 'output_'+str(int(time.time()))
        data = ''.join(data)
        wf = wave.open(filename + '.wav', 'wb')
        wf.setnchannels(1)
        wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
        wf.setframerate(16000)
        wf.writeframes(data)
        wf.close()
        return filename + '.wav'
    
    def listen(self, silenceTime = 1, previousAudio = 0.5):
        # Listen to mic and save temp WAV
        p = pyaudio.PyAudio()
        stream = p.open(format = pyaudio.paInt16,
                                  channels = 1,
                                  rate = 16000,
                                  input = True,
                                  frames_per_buffer = 1024)

        audioData = []
        currentData = ''
        rel = 16000 / 1024
        slidWin = deque(maxlen = silenceTime * rel)
        prevAudio = deque(maxlen = previousAudio * rel)

        listenSetup = False
        print "Listen class active"

        while True:
            currentData = stream.read(1024)
            slidWin.append(math.sqrt(abs(audioop.avg(currentData, 4))))

            print sum([x > self.threshold for x in slidWin])
            
            if sum([x > self.threshold for x in slidWin]) > 0:
                if listenSetup == False:
                    print "Starting recording..."
                    listenSetup = True
                audioData.append(currentData)

            elif listenSetup:
                print "Finished recording."
                filename = self.saveVoice(list(prevAudio) + audioData, p)
                words = self.d.decodeWAV(filename)
                print "Words detected: ", words

                os.remove(filename)
                listenSetup = False
                slidWin = deque(maxlen = silenceTime * rel)
                prevAudio = deque(maxlen = previousAudio * rel)
                audioData = []
                print "Reset, now listening..."

            else:
                print "Else stream..."
                prevAudio.append(currentData)