import math
import wave #bearbeiten von .wav-Dateien
import struct
import sounddevice as sd #zum abspielen des audio-arrays
import random as random #für die Rauscherzeugung
import time #nur für die Tests, um Zeit zum Anhören der Sounds einzubauen

#In .wav-Dateien wird der Ton in absoluten Werte eingetragen. Die Standart-framerate ist 44100
#das heißt für jede Sekunde an Ton gibt es 44100 Werte, die die Tonwelle über die Zeit beschreiben

class Tinnitus: #beinhaltet alle Werte, die vom Nutzer eingestellt werden
    def __init__(self, l_freq=600, r_freq=600, l_amp=1, r_amp=1, l_rausch=0, r_rausch=0, ear=0):
        self.linksFrequenz = l_freq
        self.rechtsFrequenz = r_freq
        self.linksLautstaerke = l_amp
        self.rechtsLautstaerke = r_amp
        self.linksRauschenLautstaerke = l_rausch #float von 0-1 (0 ist aus)
        self.rechtsRauschenLautstaerke = r_rausch
        self.ear = ear  # 0:both 1:left 2:right 3:links/rechts unterschiedlich
        return

#Die Klasse beinhaltet alle Werte, die zum Erstellen einer .wav-Datei benötigt werden und ein Tinnitus-Objekt, das beim Initialisieren übergeben werden muss.
#Die Audiodaten werden in das Array "audio" geschrieben
class Sound:
    def __init__(self, tinnitus, name="sound.wav", audio=None, nchannels=1, sampwidth=2, framerate=44100, comptype="NONE", compname="not compressed"):
        if audio is None:
            audio = []
        self.tinnitus = tinnitus
        self.name = name
        self.audio = audio #ein Array, in das die Sound-Werte geschrieben werden
        self.nchannels = nchannels #Zahl der audio channels (1:mono 2:stereo)
        self.sampwidth = sampwidth #Größe eines einzelnen Sound-Werts (in bytes)
        self.framerate = framerate #Abtastrate
        self.nframes = len(audio) #Anzahl der Sound-Werte -> Muss bei jeder audio-Änderung aktuallisiert werden
        self.comptype = comptype
        self.compname = compname
        return

    def neu_audio(self): #Schreibt Werte in das audio-Array. Soll später abhängig sein von den Tinnitus-Werten(Frequenz, Rauschen, ...)
        freq = self.tinnitus.linksFrequenz
        dauer_ms = 100.0
        amp = self.tinnitus.linksLautstaerke
        rauschen = self.tinnitus.linksRauschenLautstaerke

        self.audio.clear()
        num_samples = dauer_ms * (self.framerate / 1000.0)  # framerate -pro Sekunde- umgerechnet in -pro Millisekunde-

        # einen einfachen Sinus ins array schreiben
        for x in range(int(num_samples)):
            self.audio.append(amp * math.sin(2 * math.pi * freq * (x / self.framerate)))

        #das Rauschen addieren
        if(self.tinnitus.linksRauschenLautstaerke != 0):
            for x in range(int(num_samples)):
                self.audio[x] += random.random() * rauschen
        return

    def wav_speichern(self): #ezeugt/aktuallisiert die .wav-Datei
        self.neu_audio()
        #das 100ms audio-array strecken:
        for x in range(50): # entspricht 5 Sekunden
            for y in range(int(self.framerate/10)):
                self.audio.append(self.audio[y])

        wav_file = wave.open(self.name, "w")
        #erst werden die Rahmen-Parameter gesetzt
        self.nframes = len(self.audio)  # Anpassen des nframes-Parameters
        wav_file.setparams((self.nchannels, self.sampwidth, self.framerate, self.nframes, self.comptype, self.compname))

        #dann wird das audio-Array an die Datei übertragen
        for sample in self.audio:
            wav_file.writeframes(struct.pack('h', int(sample * 32767.0)))

        wav_file.close()
        return

    def play(self):
        self.neu_audio()
        sd.play(self.audio, self.framerate, loop=1)
        return



tinnitus1 = Tinnitus()
sound = Sound(tinnitus1)

if(0):
    print("======abnehmende Lautstärke==========")
    for x in range(10):
        print("  Lautstärke = ", tinnitus1.linksLautstaerke)
        sound.play()
        time.sleep(0.6)
        tinnitus1.linksLautstaerke -= 0.1
    print("\n\n")
    time.sleep(1)
    tinnitus1.linksLautstaerke = 1



if(0):
    print("=========RauschTest============")
    for x in range(10):
        tinnitus1.linksRauschenLautstaerke += 0.01
        print("  Rauschen = ", tinnitus1.linksRauschenLautstaerke)
        sound.play()
        time.sleep(1)

sd.stop()
print("ENDE")

