#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''On cherche ici à créer un son complexe en utilisant une interface avec l'utilisateur et l'analyser, en changeant les fréquences d'échantillonnage et en faisant la TF'''

##Importation des bibliothèques
import numpy as np
import matplotlib.pyplot as plt
import widgets
import wave
import math


frequence1 = float(input("Fréquence fondamentale f1(Hz) ? "))
frequence2 = 2*frequence1
frequence3 = 3*frequence1
frequence4 = 4*frequence1
niveau1 = float(input('Intensite de la fréquence fondamentale f1 (0 à 1) ? '))
niveau2 = float(input('Intensite de la fréquence harmonique f2 (0 à 1) ? '))
niveau3 = float(input('Intensite de la fréquence harmonique f3 (0 à 1) ? '))
niveau4 = float(input('Intensite de la fréquence harmonique f4 (0 à 1) ? '))


##Creation du fichier sonore
duree = 5
NomFichier = 'manote.wav'
manote = wave.open(NomFichier,'w') # appellation du fichier manote

nbCanal = 2    # stéreo
nbOctet = 1    # taille d'un échantillon : 1 octet = 8 bits
fech = 44100   # fréquence d'échantillonnage
nbEchantillon = int(duree*fech)


parametres = (nbCanal,nbOctet,fech,nbEchantillon,'NONE','not compressed')# tuple
manote.setparams(parametres)    # création de l'en-tête (44 octets)

# niveau max dans l'onde positive : +1 -> 255
# niveau max dans l'onde négative : -1 ->   0
# codage sur 256 valeurs donc niveau sonore nul à 128

amplitude1 = 128*niveau1
amplitude2 = 128*niveau2
amplitude3 = 128*niveau3
amplitude4 = 128*niveau4


#Paramètres de simulation

parameters = {'fe' : widgets.IntSlider(value=10, description='fréquence échantillonnage', min=1, max=50),
              'T'  : widgets.FloatSlider(value = 1/frequence1, description='période', min = 0.001, max =1),
              'B'  : widgets.FloatSlider(value = 0.1, description='intensité du bruit', min =0., max =1)}


D = 200. # Duree d'observation


#Définition des fonctions : étape 1 former le signal et le visualiser


def signal_initial(T, niveau1, niveau2, niveau3, niveau4):
    '''Formation du signal initial'''
    tp = np.linspace (0, D, 10000)
    T_2 = T/2
    T_3 = T/3
    T_4 = T/4
    signal_1 = niveau1*np.sin(2.0*np.pi*(1/T)*tp)
    signal_2 = niveau2*np.sin(2.0*np.pi*(1/T_2)*tp)
    signal_3 = niveau3*np.sin(2.0*np.pi*(1/T_3)*tp)
    signal_4 = niveau4*np.sin(2.0*np.pi*(1/T_4)*tp)
    
    return tp, signal_1, signal_2, signal_3,signal_4, signal_1 + signal_2 + signal_3 + signal_4

def signal_ech(T, fe , niveau1 , niveau2 , niveau3 , niveau4):
    '''Formation du signal échantillonné'''
    N = int(D * fe) + 1
    te = np.linspace(0., (N-1)/fe, N)
    T_2 = T/2
    T_3 = T/3
    T_4 = T/4
    signal_1 = niveau1*np.sin(2.0*np.pi*(1/T)*te)
    signal_2 = niveau2*np.sin(2.0*np.pi*(1/T_2)*te)
    signal_3 = niveau3*np.sin(2.0*np.pi*(1/T_3)*te)
    signal_4 = niveau4*np.sin(2.0*np.pi*(1/T_4)*te)   
    return te, signal_1, signal_2, signal_3,signal_4, signal_1 + signal_2 + signal_3 + signal_4

#Définition des fonctions : étape 2 ajouter le bruit

def bruit(B,signal):
    return signal + np.random.normal(0, B, 10000)

#Definition des fonctions : étape 3 faire la fft

def fft(fe, signal):
    n = signal.size
    fourier = np.fft.fft(signal)
    freq_e = np.fft.fftfreq(n, d=1/fe)
    freq_p = np.fft.fftfreq(n, d=D/10000)
    return freq_e, fourier, freq_p


#Paramètres de la figure

fig=plt.figure(figsize=(12,10))
ax1 = plt.subplot(212)
ax2 = plt.subplot(221)
ax3 = plt.subplot(222)

#plot et définition des widgets

def plot_data(fe,T,B):
    T = T 
    lines['Signal e'].set_data(signal_ech(T, fe , niveau1 , niveau2 , niveau3 , niveau4)[0],signal_ech(T, fe , niveau1 , niveau2 , niveau3 , niveau4)[5])
    lines['Signal p'].set_data(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[0],signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])
    a['Signal b'].set_data(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[0],bruit(B,signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5] ))
    a['fft e'].set_data(fft(fe,signal_ech(T, fe , niveau1 , niveau2 , niveau3 , niveau4)[5])[0],fft(fe,signal_ech(T, fe , niveau1 , niveau2 , niveau3 , niveau4)[5])[1].real)
    a['fft p'].set_data(fft(fe,signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])[2],fft(fe,signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])[1].real)
    texts.set_text('fréquence : f = {:1} Hz'.format(1/T))
    ax1.set_xlim(0,5*T)
    ax1.set_ylim(np.min(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])-0.2,np.max(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])+0.2)
    ax2 = plt.subplot(221)
    ax2.set_xlim(0,5*T)
    ax2.set_ylim(np.min(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])-0.2,np.max(signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])+0.2)
    ax3.set_xlim(0,np.max(fft(fe,signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])[2]))
    ax3.set_ylim(0,np.max(fft(fe,signal_initial(T, niveau1, niveau2, niveau3, niveau4)[5])[1].real))

lines = {}
lines['Signal e'], = ax1.plot([], [],'r-',lw=2,label='Signal e')
lines['Signal p'], = ax1.plot([], [],'b--',lw=2,label='Signal p')
a = {}
a['Signal b'], = ax2.plot([], [],'g',lw=2,label='Signal b')
a['fft e'], = ax3.plot([], [],'r-',lw=2,label='fft e')
a['fft p'], = ax3.plot([], [],'b--',lw=2,label='fft p')


texts=  ax1.text(0.851, 0.9, '$x=$', bbox=dict(facecolor='red', alpha=0.5), fontsize=10, transform=ax1.transAxes)
ax1.set_title("Signal d'entrée et signal échantillonné" )
ax2.set_title("Signal avec bruit")
ax3.set_title("Transformée de Fourier du signal d'entrée/échantillonné")

ax1.set_xlabel('temps (s)')
ax1.set_ylabel('Amplitude')
ax2.set_xlabel('temps (s)')
ax2.set_ylabel('Amplitude')
ax3.set_xlabel('fréquence (Hz)')
ax3.set_ylabel('Amplitude')



ax1.legend(loc="lower left")
ax2.legend(loc="lower left")
ax3.legend(loc="upper right")

param_widgets = widgets.make_param_widgets(parameters, plot_data, slider_box=[0.30, 0.0, 0.35, 0.05])
choose_widget = widgets.make_choose_plot(lines, box=[0.9,0.2,0.08, 0.2])
reset_button = widgets.make_reset_button(param_widgets,box=[0.01, 0.01, 0.08, 0.05])

print('Veuillez patienter, création du fichier son en cours...')
for i in range(0,nbEchantillon):
    # canal gauche
    # 128 seuil du zéro
    valG = wave.struct.pack('B',128+int(0.1*(amplitude1*math.sin(2.0*math.pi*frequence1*i/fech)+amplitude2*math.sin(2.0*math.pi*frequence2*i/fech)+ amplitude3*math.sin(2.0*math.pi*frequence3*i/fech)+amplitude4*math.sin(2.0*math.pi*frequence4*i/fech))))
    # canal droite
    # 128 seuil du zéro
    valD = wave.struct.pack('B',128+int(0.1*(amplitude1*math.sin(2.0*math.pi*frequence1*i/fech)+amplitude2*math.sin(2.0*math.pi*frequence2*i/fech)+amplitude3*math.sin(2.0*math.pi*frequence3*i/fech)+amplitude4*math.sin(2.0*math.pi*frequence4*i/fech))))

    manote.writeframes(valG+valG) # écriture fichier



if __name__=='__main__':
    plt.show()
