Browse Source

Stereo-Sound eingebaut und Formatierungen/Kommentare geändert

master
Heiko Ommert 3 years ago
parent
commit
6359602a4b
2 changed files with 72 additions and 60 deletions
  1. 66
    54
      TinnitusAnalyse/SoundGenerator.py
  2. 6
    6
      TinnitusAnalyse/TinnitusAnalyse_GUI.py

+ 66
- 54
TinnitusAnalyse/SoundGenerator.py View File

@@ -1,15 +1,18 @@
import math
import wave #bearbeiten von .wav-Dateien
import wave # bearbeiten von .wav-Dateien
import struct
import sounddevice as sd #zum abspielen des audio-arrays
import sounddevice as sd # zum abspielen des audio-arrays
import numpy as np
import sys #für Fehlermeldungen
import sys # für Fehlermeldungen

#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
"""---------------------------------------------------------------------------------------------------------------------
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=0, r_amp=0, l_rausch=0, r_rausch=0, ear=0):

class Tinnitus: # beinhaltet alle Werte, die vom Nutzer eingestellt werden
def __init__(self, l_freq=0, r_freq=0, l_amp=0, r_amp=0, l_rausch=0, r_rausch=0, ohr=0):
self.vorname = ""
self.nachname = ""
self.kommentar = ""
@@ -17,13 +20,11 @@ class Tinnitus: #beinhaltet alle Werte, die vom Nutzer eingestellt werden
self.rechtsFrequenz = r_freq
self.linksLautstaerke = l_amp
self.rechtsLautstaerke = r_amp
self.linksRauschenLautstaerke = l_rausch #float von 0-1 (0 ist aus)
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

def speichern(self): #speichert die Nutzerdaten in eine .csv-Datei
self.ohr = ohr # 0:both 1:left 2:right 3:links/rechts unterschiedlich

def speichern(self): # speichert die Nutzerdaten in eine .csv-Datei
datei = open("TinnitusDaten.csv", "w")

daten = "Vorname;" + self.vorname + "\n"
@@ -38,90 +39,101 @@ class Tinnitus: #beinhaltet alle Werte, die vom Nutzer eingestellt werden
datei.write(daten)
datei.close()

return

"""Sound beinhaltet alle Variablen, die zum erstellen einer .wav-Datei benötigt werden (siehe soun.wav_speichern())
"""---------------------------------KLASSE: SOUND-----------------------------------------------------------------------
Sound beinhaltet alle Variablen, die zum erstellen einer .wav-Datei benötigt werden (siehe soun.wav_speichern())
Das 'sound_obj' ist für das dynamische abspielen zuständig (siehe sound.play())
Beim Initialisieren muss eine Tinnitus-Objekt übergeben werden"""
Beim Initialisieren muss eine Tinnitus-Objekt übergeben werden
---------------------------------------------------------------------------------------------------------------------"""


class Sound:
def __init__(self, tinnitus, name="sound.wav", audio=None, nchannels=1, sampwidth=2, framerate=44100, comptype="NONE", compname="not compressed", mute=True):
def __init__(self, tinnitus, name="sound.wav", audio=None, nchannels=1, sampwidth=2, framerate=44100,
comptype="NONE", compname="not compressed", mute=True):
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.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
self.mute = True # wenn der mute boolean auf true gesetzt ist, sollte kein Ton ausgegeben werden
self.sound_obj = sd.OutputStream(channels=2, callback=self.callback, samplerate=self.framerate) #Objekt fürs Abspielen (siehe sound.play())
self.start_idx = 0 #wird für sound_obj benötigt
return
self.mute = mute # wenn der mute boolean auf true gesetzt ist, sollte kein Ton ausgegeben werden
self.sound_obj = sd.OutputStream(channels=2, callback=self.callback,
samplerate=self.framerate) # Objekt fürs Abspielen (siehe sound.play())
self.start_idx = 0 # wird für sound_obj benötigt

def wav_speichern(self): #ezeugt/aktuallisiert die .wav-Datei
def wav_speichern(self): # ezeugt/aktuallisiert die .wav-Datei
wav_file = wave.open(self.name, "w")
print("Sound wird als .wav-Datei gespeichert. Bitte warten...\nDer Vorgang kann ca. 30 Sekunden dauern")

#zuerst muss ein Array mit Audiodaten gefüllt werden
# zuerst muss ein Array mit Audiodaten gefüllt werden
audio = []
freq = self.tinnitus.linksFrequenz
dauer_ms = 10000.0 #10 Sekunden
dauer_ms = 10000.0 # 10 Sekunden
amp = self.tinnitus.linksLautstaerke
rauschen = self.tinnitus.linksRauschenLautstaerke

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

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

if(rauschen): #das Rauschen addieren
if rauschen: # das Rauschen addieren
for x in range(int(num_samples)):
audio[x] += (np.random.rand() - 0.5) * rauschen


#erst werden die Rahmen-Parameter gesetzt
# erst werden die Rahmen-Parameter gesetzt
self.nframes = len(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
# dann wird das audio-Array an die Datei übertragen
for sample in audio:
wav_file.writeframes(struct.pack('h', int(sample * 32767.0)))

wav_file.close()
print("Speichern beendet.")
return

"""Die Objekt-Funktion __enter__() startet die asynchrone Soundwiedergabe. Sie ruft dabei immer wieder die Funktion
"""Die Objekt-Funktion 'start()' startet die asynchrone Soundwiedergabe. Sie ruft dabei immer wieder die Funktion
sound.callback() auf. Daher können die dort genutzten Variablen dynamisch geändert werden. """

def play(self):
if not self.mute: # NEVER play sound when patient mutes GUI
self.sound_obj.__enter__()
return
if not self.mute: # NEVER play sound when patient mutes GUI
self.sound_obj.start()

def stop(self):
self.sound_obj.__exit__() #beendet die asynchrone Soundwiedergabe
return
self.sound_obj.stop() # beendet die asynchrone Soundwiedergabe

"""Die Funktion callback() erzeugt bei jedem Aufruf die Audiodaten, abhängig von den aktuellen Tinnitus-Variablen.
Die errechneten Werte werden in das NumPy-Array 'outdata' geschrieben """
#momentan nur Mono. Es werden die Werte des linken Ohrs genutzt

# momentan nur Mono. Es werden die Werte des linken Ohrs genutzt
def callback(self, outdata, frames, time, status):
if status: #gibt Warnungen aus, wenn das Soundobjekt auf Fehler stößt (hauptsächlich over/underflow wegen timingproblemen)
if status: # Warnungen, wenn das Soundobj. auf Fehler stößt (hauptsächlich over/underflow wg. Timingproblemen)
print(status, file=sys.stderr)
t = (self.start_idx + np.arange(frames)) / self.framerate
t = t.reshape(-1, 1)

#Sinuston ins Array schreiben
outdata[:] = self.tinnitus.linksLautstaerke * np.sin(2 * np.pi * self.tinnitus.linksFrequenz * t)

#Rauschen addieren
if(self.tinnitus.linksRauschenLautstaerke):
for x in range(len(outdata)):
rand = (np.random.rand() - 0.5) * self.tinnitus.linksRauschenLautstaerke
outdata[x] += rand
# Sinus ins Array schreiben: f(t) = A * sin(2 * pi * f * t)
for x in range(frames):
# links:
if self.tinnitus.linksLautstaerke:
outdata[x][0] = self.tinnitus.linksLautstaerke * np.sin(2 * np.pi * self.tinnitus.linksFrequenz *
((x + self.start_idx) / self.framerate))
# rechts:
if self.tinnitus.rechtsLautstaerke:
outdata[x][1] = self.tinnitus.rechtsLautstaerke * np.sin(2 * np.pi * self.tinnitus.rechtsFrequenz *
((x + self.start_idx) / self.framerate))

# Rauschen addieren
for x in range(frames):
rand = (np.random.rand() - 0.5) * self.tinnitus.linksRauschenLautstaerke
#links:
if self.tinnitus.linksRauschenLautstaerke:
outdata[x][0] += rand
#rechts:
if self.tinnitus.rechtsRauschenLautstaerke:
outdata[x][1] += rand

self.start_idx += frames


+ 6
- 6
TinnitusAnalyse/TinnitusAnalyse_GUI.py View File

@@ -42,20 +42,20 @@ def links_scale_rauschen_bandbreite_change(self):


def rechts_scale_lautstärke_change(self):
rechtsLautstärke = float(rechtsScaleLautstärke.get())
print("Rechts Lautstärke =", rechtsLautstärke)
tinnitus.rechtsLautstaerke = float(rechtsScaleLautstärke.get()/100)
print("Rechts Lautstärke =", tinnitus.rechtsLautstaerke, "%")
sound.play()


def rechts_scale_frequenz_change(self):
rechtsFrequenz = float(rechtsScaleFrequenz.get())
print("Rechts Frequenz= ", rechtsFrequenz)
tinnitus.rechtsFrequenz = float(rechtsScaleFrequenz.get()*1000)
print("Rechts Frequenz= ", tinnitus.rechtsFrequenz, " Hz")
sound.play()


def rechts_scale_rauschen_lautstärke_change(self):
rechtsRauschenLautstärke = float(rechtsScaleRauschenLautstärke.get())
print("Rechts Rauschen Lautstärke = ", rechtsRauschenLautstärke)
tinnitus.rechtsRauschenLautstaerke = float(rechtsScaleRauschenLautstärke.get()/1000)
print("Rechts Rauschen Lautstärke = ", rechtsRauschenLautstärke*1000, "%")
sound.play()



Loading…
Cancel
Save