# -*- coding: utf-8 -*-
"""Analyse du micro et stockage des parametres pour le chat vocal"""
import audioop
import time
from math import fabs
import cPickle as pickle #lecture/ecriture d'objets dans un fichier

#modules complémentaires
import pymedia.audio.sound as sound


class AnaSon():
    """analyse et stocke les parametres d'entree du son (version pymedia)"""
    def __init__(self):
        """initialisation des parametres par defauts"""
        #puissance moyenne du son en silence
        self.pMoy_silence = 1800
        #ecarts liees aux parasites
        self.ecartSilence = 500
        #puissance moyenne du son en parlant
        self.pMoy_parle = 16000
        #coeff de puissance
        self.coeffP = 1.00
        #puissance de reference
        self.pRef = 20000
        #forme d'onde (liste des puissances) en silence et en parlant
        self.formeS = []
        self.formeP = []
        #duree des tests
        self.duree = 5
        #peripheriques par defaut:
        self.IDmicro = 0

        #pour le traitement du son:
        self.compte = 0

        #affiche des infos
        self.affichage = True
        
        #fichier de sauvegarde
        self.fichier = "param_micro"
        self.ecoute = False

        #pour enregistrement de la reception
        #self.enregistrement = open( "ResultatAnalyse.mp3", 'wb' )

    def recup(self):
        """recupere si possible les parametres enregistres"""
        try:
             with open(self.fichier, 'rb') as f:
                 tmp = pickle.load(f)
             f.close()
             print("Parametres récupérés")
        except IOError:
            tmp = self
            print("Pas de parametres enregistres, parametres par defaut utilises")
        return tmp
        
    def sauver(self):
        """sauvegarde les parametres analyses"""
        with open(self.fichier, 'wb') as f:
           pickle.dump(self, f, -1)
        f.close()
        print("Parametres sauvegardes.")

    def analyser(self):
        """lance l'analyse du son"""
        print("\n*** Analyse du micro ***\n")
        
        #phase 1: quel micro?
        print(sound.getIDevices())
        self.IDmicro = input("\nMicro par defaut? (id) > ")
        micro = sound.Input( 16000, 1, sound.AFMT_S16_LE, self.IDmicro )
        micro.start()
        sortie = sound.Output( 16000, 1, sound.AFMT_S16_LE )
        enregistrement = open( "ResultatsAnaSon.mp3", 'wb' )
        
        # phase 2 : parasites
        #liste des donnees recues au cours de l'analyse
        frames_test = []
        
        #boucle de reception
        print("Test des parasites: ne parlez pas (env. {} sec)\n".format(self.duree+1))
        pause = raw_input("Appuyez sur Entree pour lancer: \n")
        t0 = time.time()
        while time.time() - t0 < self.duree:
           son = micro.getData()
           if son and len(son):
              frames_test.append(son)
              #audioop.rms renvoie la puissance moyenne du son
              self.formeS.append(audioop.rms(son,2))
        #on enleve la premiere valeur qui n'est generalement pas representative:
        del frames_test[0]
        del self.formeS[0]
        print("{}\n".format(self.formeS)) 
        
        #donnees utilisees pour l'attenuation du son lors des silences:
        self.pMoy_silence = audioop.rms(b''.join(frames_test),2)
        self.ecartMax = 0
        
        ecart_mesure = 0
        for son in frames_test:
            if fabs(audioop.rms(son,2) - self.pMoy_silence) > ecart_mesure:
                ecart_mesure = fabs(audioop.rms(son,2) - self.pMoy_silence)
        if ecart_mesure > 10:
            self.ecartSilence = ecart_mesure
            
        # phase 3 : parle
        frames_test = []
        print("Test de la voix: parlez normalement (env. {} sec)\n ".format(self.duree+1))
        pause = raw_input("Appuyez sur Entree pour lancer: \n")
        t0 = time.time()
        while time.time() - t0 < self.duree:
           son = micro.getData()
           if son and len(son):
              self.formeP.append(audioop.rms(son,2))
              if audioop.rms(son,2) > (self.pMoy_silence + self.ecartSilence):
                 frames_test.append(son)                 

        #on enleve la premiere valeur qui n'est generalement pas representative:
        del self.formeP[0]
        print("{}\n".format(self.formeP))
        
        if len(frames_test)>0:
           del frames_test[0]        
           self.pMoy_parle = audioop.rms(b''.join(frames_test),2) 
           #mise a jour du coeff de puissance:
           if self.pMoy_parle != 0:        
              self.coeffP = self.pRef / self.pMoy_parle
              if self.coeffP < 0.2:
                  self.coeffP = 0.20
              elif self.coeffP > 4:
                  self.coeffP = 4.00
        else:
            print("\n (!) Erreur: la puissance de la voix est insuffisante pour etre detectee")
        print("\n*** Fin de l'analyse ***\n")
        micro.stop()
        enregistrement.close()

        self.sauver() 

    def traitement(self, data):
        """renvoie la donnee sonore traitee selon les parametres utilises"""
        #est-on dans la 'zone de silence'?
        kS = 1
        retour = None
        seuil_iterations = 3
        if audioop.rms(data,2) <= self.pMoy_silence + self.ecartSilence:
              #on ne diminue la puissance du son qu'apres un certain nombre d'iterations (4 ici)
              self.compte += 1
              if self.compte > seuil_iterations:
                  if self.affichage and self.compte == seuil_iterations + 1:
                      print("\n-> silence")
                  kS = 0.2    
        else:
              if self.affichage and self.compte != 0:
                  print("\n-> parle")
              self.compte = 0
              #retour = audioop.mul(data, 2, (self.coeffP))  
              kS = 1
        retour = audioop.mul(data, 2, (kS * self.coeffP))        
        return retour                
     
    def ecouterMicro(self):
        """ecouter son micro"""
        micro = sound.Input( 16000, 1, sound.AFMT_S16_LE, self.IDmicro )
        micro.start()
        sortie = sound.Output( 16000, 1, sound.AFMT_S16_LE )

        t0 = time.time()
        #while time.time() - t0 < self.duree:
        while True:
            son = micro.getData()
            if son and len(son):
              son_traite = self.traitement(son)
              #print("{} - {}".format(audioop.rms(son,2), audioop.rms(son_traite,2)))
              sortie.play(son_traite)
              
        micro.stop()
        
    def __repr__(self):
        """affiche les parametres utilises"""
        chaine = "\n*** Parametres utilises ***\n"\
                 "\n    Puissance moyenne en silence: {} "\
                 "\n    Amplitude parasites: {} "\
                 "\n    Puissance moyenne en parlant: {} "\
                 "\n    Multiplicateur applique: {} "\
                 "".format(self.pMoy_silence, self.ecartSilence, self.pMoy_parle, self.coeffP)     
        return chaine  



######### si lancement direct ########
if __name__ == "__main__":
   a = AnaSon()
   a.analyser()
   #a = None
   #a = AnaSon()
   #a = a.recup()
   print(a)
   #a.ecouterMicro()
   #a.analyser()
   pause = raw_input("appuyez sur entree")
   


