Browse Source

kleine Aenderungen:

 -Die samples werden nach dem Filtern jetzt auf einen maximalen wert von 1 normiert
 -Layout der GUI verbessert
 -Feedback verbessert (v. a. Filterstatus)

ACHTUNG: Der Filter liefert bei niedrigen Filterfrequenzen unendlich hohe Werte, was das Filtern unmoeglich macht
Fehlt: Filter fuers Rauschen
master
Heiko Ommert 4 years ago
parent
commit
23784cc6f7
2 changed files with 92 additions and 37 deletions
  1. 47
    8
      TinnitusAnalyse/SoundGenerator.py
  2. 45
    29
      TinnitusAnalyse/TinnitusAnalyse_GUI.py

+ 47
- 8
TinnitusAnalyse/SoundGenerator.py View File

self.start_idx = 0 # wird für sound_obj benötigt self.start_idx = 0 # wird für sound_obj benötigt
self.music_samplerate = 0 # die samplerate der ausgewählten Musikdatei self.music_samplerate = 0 # die samplerate der ausgewählten Musikdatei
self.music_data = 0 # das Numpy Array der ausgewählten Musikdatei self.music_data = 0 # das Numpy Array der ausgewählten Musikdatei
self.filterfortschritt = 0 # siehe musik_filtern(), zwischen 0 und 100, wird für die feedback-fkt gebraucht
self.filterfortschritt = 0, 0. # für feedback-fkt, 1.Position: Abschnitt-Nmr, 2.Positon: Speicherfortschritt




def wav_speichern(self): # ezeugt/aktuallisiert die .wav-Datei def wav_speichern(self): # ezeugt/aktuallisiert die .wav-Datei
for x in range(self.nframes): # geht jeden Sample-Wert der Musikdatei einzeln durch for x in range(self.nframes): # geht jeden Sample-Wert der Musikdatei einzeln durch
# Die Audiodaten müssen von float in einen passenden int-Wert umgerechnet werden # Die Audiodaten müssen von float in einen passenden int-Wert umgerechnet werden
packedMusic.append(struct.pack('h', int(audio[x][0] * 32767.0))) packedMusic.append(struct.pack('h', int(audio[x][0] * 32767.0)))
packedMusic.append(struct.pack('h', int(audio[x][0] * 32767.0)))
packedMusic.append(struct.pack('h', int(audio[x][1] * 32767.0)))


value_str = b"".join(packedMusic) value_str = b"".join(packedMusic)
wav_obj.writeframes(value_str) wav_obj.writeframes(value_str)
2. Die digitalen Filter erstellen und die Tinnitus Frequenz aus der Audiodatei "herausschneiden" 2. Die digitalen Filter erstellen und die Tinnitus Frequenz aus der Audiodatei "herausschneiden"
3. Die fertigen Audiodatei als .wav Datei speichern 3. Die fertigen Audiodatei als .wav Datei speichern
""" """
nframes = len(self.music_data) # Gesamtanzahl der Frames in der Musikdatei


# ------------1. Die nötigen Informationen über den Tinnitus aus der .csv Datei herausholen--------------------- # ------------1. Die nötigen Informationen über den Tinnitus aus der .csv Datei herausholen---------------------
self.filterfortschritt = 1, 0 # der erste schritt
csvstring = open("TinnitusDaten.csv").read() csvstring = open("TinnitusDaten.csv").read()
tinnitus_data = csvstring.split("\n") tinnitus_data = csvstring.split("\n")


rl = float(rl[1]) rl = float(rl[1])


# -------- 2. Die digitalen Filter erstellen und die Tinnitus Frequenz aus der Audiodatei "herausschneiden------ # -------- 2. Die digitalen Filter erstellen und die Tinnitus Frequenz aus der Audiodatei "herausschneiden------
self.filterfortschritt = 2, 0 # der zweite schritt
start_time = time.time() # einen Timer laufen lassen um zu sehen wie lange Filterung dauert start_time = time.time() # einen Timer laufen lassen um zu sehen wie lange Filterung dauert


self.music_data = self.music_data/32767 * 0.8 # convert array from int16 to float
self.music_data = self.music_data/32767 # convert array from int16 to float
""" OLD IIR Notch Filter 2nd Order---------------------------------------------------------------------- """ OLD IIR Notch Filter 2nd Order----------------------------------------------------------------------
w0 = float(lf / (self.music_samplerate / 2)) # Frequency to remove from a signal. If fs is specified, this is w0 = float(lf / (self.music_samplerate / 2)) # Frequency to remove from a signal. If fs is specified, this is
in the same units as fs. By default, it is a normalized scalar that must satisfy 0 < w0 < 1, with w0 = 1 in the same units as fs. By default, it is a normalized scalar that must satisfy 0 < w0 < 1, with w0 = 1
endTimeFiltering = time.time() endTimeFiltering = time.time()
print("benötigte Zeit zum Filtern rechts Ohr =", endTimeFiltering - start_time, "s") print("benötigte Zeit zum Filtern rechts Ohr =", endTimeFiltering - start_time, "s")


# ------------------------- 3. Die fertigen Audiodatei als .wav Datei speichern --------------------------------
#----------------------- 3. Maxima finden und Samples auf 1 normieren ----------------------------
self.filterfortschritt = 3, 0 # der dritte schritt

#Maximum finden (Funktion max(...) ist minimal schneller, macht aber Probleme beim Feedback)
start_time = time.time()
max_ges = 0
for i in range(nframes):
if max_ges < abs(music_links[i]):
max_ges = abs(music_links[i])
if max_ges < abs(music_rechts[i]):
max_ges = abs(music_rechts[i])
if i % 50000 == 0:
fortschritt = i / nframes * 100
self.filterfortschritt = 3, round(fortschritt, 1)
print(" max: ", self.filterfortschritt[1], "%")
end_time = time.time()
print("Zeitaufwand Maxima-Suche: ", end_time - start_time)

#auf 4 Nachkommastellen aufrunden
start_time = time.time()
max_ges = int(max_ges * 10000)
max_ges += 1
max_ges /= 10000
end_time = time.time()
print("Zeitaufwand Maximum runden: ", end_time - start_time)

#Alle samples normieren
start_time = time.time()
music_links /= max_ges
music_rechts /= max_ges
end_time = time.time()
print("Zeitaufwand samples normieren: ", end_time - start_time)


# ------------------------- 4. Die fertigen Audiodatei als .wav Datei speichern --------------------------------
self.filterfortschritt = [4, 0] # der vierte Schritt
start_time = time.time() start_time = time.time()
wav_obj = wave.open("MyTinnitusFreeSong.wav", "w") wav_obj = wave.open("MyTinnitusFreeSong.wav", "w")

# Rahmenparameter für die .wav-Datei setzen # Rahmenparameter für die .wav-Datei setzen
nframes = len(self.music_data) #Gesamtanzahl der Frames in der Musikdatei
wav_obj.setparams((self.nchannels, self.sampwidth, self.music_samplerate, nframes, self.comptype, self.compname)) wav_obj.setparams((self.nchannels, self.sampwidth, self.music_samplerate, nframes, self.comptype, self.compname))


"""The values are stored in a temporary list, and when the process is finished, they are joined together into """The values are stored in a temporary list, and when the process is finished, they are joined together into


# wav_obj.writeframes(struct.pack('h', int(music_links[x] * 32767.0))) # Werte für links und rechts werden bei # wav_obj.writeframes(struct.pack('h', int(music_links[x] * 32767.0))) # Werte für links und rechts werden bei
# wav_obj.writeframes(struct.pack('h', int(musicRechts[x] * 32767.0))) # wav abwechselnd eingetragen # wav_obj.writeframes(struct.pack('h', int(musicRechts[x] * 32767.0))) # wav abwechselnd eingetragen
if tinnitus_data % 10000 == 0:
if tinnitus_data % 50000 == 0:
fortschritt = tinnitus_data/nframes*100 fortschritt = tinnitus_data/nframes*100
self.filterfortschritt = round(fortschritt, 1)
print(" ", self.filterfortschritt, "%")
self.filterfortschritt = 4, round(fortschritt, 1)
print(" samples: ", self.filterfortschritt[1], "%")


end_time = time.time() end_time = time.time()
print("Zeitaufwand für das packen der einzelnen Samples =", end_time - start_time, "s") print("Zeitaufwand für das packen der einzelnen Samples =", end_time - start_time, "s")
wav_obj.close() wav_obj.close()


print("Speichern beendet.") print("Speichern beendet.")
self.filterfortschritt = 5, 0 #Nach erfolgreichem Filtern Fortschritt zur Bestätigung auf 5 setzen
# # Plot (hilfreich für Filterentwurf) # # Plot (hilfreich für Filterentwurf)
# freq, h = signal.freqz(b, a, fs=self.music_samplerate) # freq, h = signal.freqz(b, a, fs=self.music_samplerate)
# fig, ax = plt.subplots(2, 1, figsize=(8, 6)) # fig, ax = plt.subplots(2, 1, figsize=(8, 6))

+ 45
- 29
TinnitusAnalyse/TinnitusAnalyse_GUI.py View File

else: else:
try: try:
unten_button_stop_press() # Wiedergabe beenden, durch den Rechenaufwand gibt es sonst Wiedergabeprobleme unten_button_stop_press() # Wiedergabe beenden, durch den Rechenaufwand gibt es sonst Wiedergabeprobleme
feedback("Speichere Sound als '.wav'-Datei. Bitte warten...")
tinnitus.vorname = untenEntryVorname.get() tinnitus.vorname = untenEntryVorname.get()
tinnitus.nachname = untenEntryNachname.get() tinnitus.nachname = untenEntryNachname.get()
tinnitus.kommentar = untenTextKommentar.get("1.0", END) tinnitus.kommentar = untenTextKommentar.get("1.0", END)
tinnitus.speichern() tinnitus.speichern()
feedback("Speichere Sound als '.wav'-Datei. Bitte warten...")
sound.wav_speichern() sound.wav_speichern()
feedback("Daten erfolgreich gespeichert. Siehe: " + sound.wav_name, "white", "green") feedback("Daten erfolgreich gespeichert. Siehe: " + sound.wav_name, "white", "green")
except: except:
right of the GUI) in the text widget. The parameter color is also a string and defines the font color. Same with right of the GUI) in the text widget. The parameter color is also a string and defines the font color. Same with
background. Honestly this function is way too complicated, but Tkinter has no nicer/easier builtin way of doing the background. Honestly this function is way too complicated, but Tkinter has no nicer/easier builtin way of doing the
coloring nicely """ coloring nicely """

feedback.lineCounter += 1 # in order to color the texts nicely we need to count the lines of text we add feedback.lineCounter += 1 # in order to color the texts nicely we need to count the lines of text we add
untenFeedbackText.config(state=NORMAL) # activate text field (otherwise it is readonly) untenFeedbackText.config(state=NORMAL) # activate text field (otherwise it is readonly)




def unten_button_filtere_tinnitus_aus_musik(): def unten_button_filtere_tinnitus_aus_musik():
print("button filtere tinnitus aus musik pressed") print("button filtere tinnitus aus musik pressed")
try:
print(untenTextMusikDatei.get('1.0', END))
if untenTextMusikDatei.get('1.0', END) == "Einen Song deiner Wahl hier auswählen\n":
feedback("Wähle zuerst eine Musikdatei aus", "white", "red")
else:
unten_button_stop_press() # Wiedergabe beenden, durch den Rechenaufwand gibt es sonst Wiedergabeprobleme
feedback("Starte Filtervorgang (dies kann etwas dauern)...", "blue") feedback("Starte Filtervorgang (dies kann etwas dauern)...", "blue")
# Filtern in extra thread, damit sich die GUI nicht aufhängt: (daemon beendet den Thread, wenn das Hauptprogramm beendet wird)
filter_thread = threading.Thread(target=sound.musik_filtern, daemon=True)
filter_thread.start()

while filter_thread.is_alive() == True:
fb = "Status: " + str(sound.filterfortschritt) + "%"
feedback(fb)
time.sleep(0.2)
print("-- filtern beendet --")
feedback("Filtervorgang erfolgreich abgeschlossen. \n"
"Audiodatei unter dem Namen MyTinnitusFreeSong.wav erstellt", "white", "green")
except:
feedback("Fehlgeschlagener Filterversuch. Drücke zuerst den Speichern Knopf"
"Stelle sicher, dass die Lautstärke mindestens einer Seite über 0"
"gestellt ist. Sonst gehen wir davon aus, dass auf diesem Ohr kein Tinnitus vorliegt.", "red", "white")

try:
# Filtern in extra thread, damit sich die GUI nicht aufhängt: (daemon beendet den Thread, wenn das Hauptprogramm beendet wird)
filter_thread = threading.Thread(target=sound.musik_filtern, daemon=True)
filter_thread.start()
time.sleep(3) # Zeit, damit man das Feedback lesen kann, bevor es gelöscht wird (siehe übernächste Zeile)

while filter_thread.is_alive():
feedback.lineCounter = 11 # "Workaround" um Zeilen überschreiben zu können
if sound.filterfortschritt[0] > 2: #Nur bei dem 3. und 4. Schritt wird der Fortschritt in Prozent angezeigt
fb = "Schritt " + str(sound.filterfortschritt[0]) + " von 4 (" + str(sound.filterfortschritt[1]) + "%)"
else:
fb = "Schritt " + str(sound.filterfortschritt[0]) + " von 4"
feedback(fb)
if sound.filterfortschritt[0] == 5: #ist 5, wenn erfolgreich gefiltert wurde
print("-- filtern beendet --")
feedback("Filtervorgang erfolgreich abgeschlossen. \n"
"Audiodatei unter dem Namen MyTinnitusFreeSong.wav erstellt", "white", "green")
else:
print("Fehler bei Filterfunktion. Siehe Compiler-Meldungen")
feedback("Fehlgeschlagener Filterversuch!", "red", "white")
except:
feedback("Fehlgeschlagener Filterversuch. Drücke zuerst den Speichern Knopf"
"Stelle sicher, dass die Lautstärke mindestens einer Seite über 0"
"gestellt ist. Sonst gehen wir davon aus, dass auf diesem Ohr kein Tinnitus vorliegt.", "red",
"white")




""" Initialisierungen """ """ Initialisierungen """
untenLabelOhrenSynchro2.grid(column=2, row=0, sticky=(N + W + E + S)) untenLabelOhrenSynchro2.grid(column=2, row=0, sticky=(N + W + E + S))
untenButtonOhrenSynchro = Button(untererFrame, text="Bestätigen", untenButtonOhrenSynchro = Button(untererFrame, text="Bestätigen",
command=unten_button_ohren_synchro) command=unten_button_ohren_synchro)
untenButtonOhrenSynchro.grid(column=3, row=0, sticky=(N + W + E + S))
untenButtonOhrenSynchro.grid(column=3, row=0, sticky=(N + S))


#----------- PLAY BUTTON #----------- PLAY BUTTON
untenButtonPlay = Button(untererFrame, text="PLAY", font="bold", relief="raised", bg="green", fg="white", untenButtonPlay = Button(untererFrame, text="PLAY", font="bold", relief="raised", bg="green", fg="white",
command=unten_button_play_press) command=unten_button_play_press)
untenButtonPlay.grid(column=8, row=0, sticky=(N + W + E + S))
untenButtonPlay.grid(column=7, row=0, sticky=(N + W + E + S))


#------------STOP BUTTON------------- #------------STOP BUTTON-------------
untenButtonStop = Button(untererFrame, text="STOP", font="bold", relief="raised", bg="red", fg="white", untenButtonStop = Button(untererFrame, text="STOP", font="bold", relief="raised", bg="red", fg="white",
command=unten_button_stop_press) command=unten_button_stop_press)
untenButtonStop.grid(column=9, row=0, sticky=(N + W + E + S))
untenButtonStop.grid(column=8, row=0, sticky=(N + W + E + S))


# ----------- ABTRENNSTRICHE ---------------- # ----------- ABTRENNSTRICHE ----------------
untenSeparator = Separator(untererFrame, orient="horizontal") untenSeparator = Separator(untererFrame, orient="horizontal")
# ------------ KOMMENTAR ---------------- # ------------ KOMMENTAR ----------------
untenLabelKommentar = Label(untererFrame, text="weitere Kommentare:") untenLabelKommentar = Label(untererFrame, text="weitere Kommentare:")
untenLabelKommentar.grid(column=0, row=4, sticky=W) untenLabelKommentar.grid(column=0, row=4, sticky=W)
untenTextKommentar = Text(untererFrame, height=10, width=50) # create a field where u can enter text
untenTextKommentar.grid(column=1, row=4, columnspan=3, rowspan=3)
untenLabelKommentar = Label(untererFrame, text="(optional)")
untenLabelKommentar.grid(column=0, row=5, sticky=N)
untenTextKommentar = Text(untererFrame, height=10, width=60) # create a field where u can enter text
untenTextKommentar.grid(column=1, row=4, sticky=W, columnspan=3, rowspan=3)


# ----------- SPEICHERN -------------------- # ----------- SPEICHERN --------------------
untenButtonSpeichern = Button(untererFrame, text="Speichern", font="bold", untenButtonSpeichern = Button(untererFrame, text="Speichern", font="bold",
command=unten_button_speichern_press) command=unten_button_speichern_press)
untenButtonSpeichern.grid(column=4, row=6, sticky=S)
untenButtonSpeichern.grid(column=4, row=6, sticky=(S+E+W))




"""--------------------------------------UNTERER RECHTER FRAME-------------------------------------------------------""" """--------------------------------------UNTERER RECHTER FRAME-------------------------------------------------------"""


# -------------- LOAD MUSIC FILE-------------- # -------------- LOAD MUSIC FILE--------------
untenTextMusikDatei = Text(untererFrame, height=1, width=50) untenTextMusikDatei = Text(untererFrame, height=1, width=50)
untenTextMusikDatei.grid(column=0, row=7, sticky=(N+S+E+W), columnspan=6)
untenTextMusikDatei.grid(column=1, row=7, sticky=(N+S+E+W), columnspan=4)
untenTextMusikDatei.insert(INSERT, "Einen Song deiner Wahl hier auswählen") # insert selected file path to text widget untenTextMusikDatei.insert(INSERT, "Einen Song deiner Wahl hier auswählen") # insert selected file path to text widget
untenTextMusikDatei.config(state=DISABLED) # activate text field (otherwise it is readonly)
untenTextMusikDatei.config(state=DISABLED, font=("Arial", 8)) # activate text field (otherwise it is readonly)


untenButtonMusikDateiLaden = Button(untererFrame, text="Musikdatei auswählen", untenButtonMusikDateiLaden = Button(untererFrame, text="Musikdatei auswählen",
command=unten_button_musikdatei_laden_press) command=unten_button_musikdatei_laden_press)
untenButtonMusikDateiLaden.grid(column=7, row=7, sticky=(N+S+E+W))
untenButtonMusikDateiLaden.grid(column=4, row=7, sticky=(N+S+E+W))




#------------BUTTON FILTERE TINNITUS AUS MUSIK----------------- #------------BUTTON FILTERE TINNITUS AUS MUSIK-----------------
untenButtonFiltereTinnitusAusMusik = Button(untererFrame, text="Filtere Tinnitus Frequenzen aus Musik",
untenButtonFiltereTinnitusAusMusik = Button(untererFrame, text="Filtere Tinnitus-Frequenzen aus Musik",
command=unten_button_filtere_tinnitus_aus_musik, font="bold", command=unten_button_filtere_tinnitus_aus_musik, font="bold",
relief="raised", bg="blue", fg="white",) relief="raised", bg="blue", fg="white",)
untenButtonFiltereTinnitusAusMusik.grid(column=0, row=9, sticky=(N+S+E+W))
untenButtonFiltereTinnitusAusMusik.grid(column=3, row=9, sticky=(N+S+E+W), columnspan=3)




root.mainloop() root.mainloop()

Loading…
Cancel
Save