Skip to content

Instantly share code, notes, and snippets.

@FabulousCodingFox
Created June 3, 2022 17:56
Show Gist options
  • Save FabulousCodingFox/af37aeb69809c1f7925dcde07532b1e1 to your computer and use it in GitHub Desktop.
Save FabulousCodingFox/af37aeb69809c1f7925dcde07532b1e1 to your computer and use it in GitHub Desktop.
A UI Interface generating and playing certain frequencies using a speaker
# Alle notwendigen Module importieren
import numpy as np
import wave, os, pygame, tkinter
from time import perf_counter
#############################################################################################################
# Ein Dictionary um alle Sounds zu speichern
soundBuffer = {}
# Eine .wav Datei mit einer bestimmten Frequenz erstellen
def createWavFile(freq=50, samples=44100, length=5):
freq = float(freq)
# calculate the length of the wav file
nSamples = samples * length #44100 Samples = CD Qualität = 1 Sekunde
# create the raw waveform data
x = np.arange(nSamples)/samples
vals = np.sin(2*np.pi*freq*x)
data = np.array(vals*32767, dtype=np.int16).tobytes()
# create the wav file
wavFile = os.path.join(os.path.dirname(__file__),"wav/", "{}hz.wav".format(freq))
w = wave.open(wavFile, "wb")
w.setnchannels(1)
w.setsampwidth(2)
w.setframerate(samples)
w.writeframes(data)
w.close()
# Die Datei im Soundbuffer als pygame.moxer.Sound Objekt speichern
soundBuffer[float(freq)] = pygame.mixer.Sound(wavFile)
# Den Pfad zur Datei zurückgeben
return wavFile
# Mehrere .wav Dateien erstellen
def generateWavFiles(start:int=40,end:int=80,step:int=1)->list[str]:
print("Generiert Sounds... [0/0] 0%")
filenames = []
i:int = 0
while start+i <= end:
filenames.append(createWavFile(start+i))
print(
"Generiert Sounddateien... [{}{}/{}] {}%".format(
'0'*(len(str(int((end-start)//step)))-len(str(int(i//step)))), # 0-padding
int(i//step), # Bisherige Anzahl
int((end-start)//step), # Gesamtanzahl
int(((i//step)/((end-start)//step))*100) # Prozent
)
)
i += step
return filenames
# Spielt einen Sound mit einer bestimmten Frequenz
def play(freq):
freq = float(freq)
# Wenn der Sound noch nicht im Soundbuffer ist, erstellen
wavePath = os.path.join(os.path.dirname(__file__), "{}hz.wav".format(freq))
if not os.path.exists(wavePath): wavePath = createWavFile(freq=freq)
pygame.mixer.stop()
soundBuffer[freq].play(loops=3600, maxtime=0, fade_ms=0) # 3600 Wiederholungen = 1 Stunde
# Den Pygame Soundplayer initialisieren
pygame.mixer.pre_init(44100,-16,1,4096)
pygame.mixer.init()
#############################################################################################################
# Oberen und unteren Frequenzbereich festlegen
frequencySettings = {
"top": 80.0,
"bottom":5.0,
"step": 1,
}
currentFrequency = frequencySettings["bottom"]
currentPeriod = 1000 / currentFrequency
selectedFrequency = currentFrequency
selectedPeriod = currentPeriod
totalFrequencies = int((frequencySettings["top"]-frequencySettings["bottom"])/frequencySettings["step"])
# Genreiere einen Orddner, in dem alle .wav Dateien gespeichert werden, sofern nicht vorhanden
if not os.path.exists(os.path.join(os.path.dirname(__file__),"wav/")):
os.mkdir(os.path.join(os.path.dirname(__file__),"wav/"))
# Generiere alle .wav Dateien, sofern noch nicht vorhanden
if not os.path.exists(os.path.join(os.path.dirname(__file__),"wav/","{}hz.wav".format(float(frequencySettings["bottom"])))):
generateWavFiles(start=frequencySettings["bottom"],end=frequencySettings["top"],step=frequencySettings["step"])
#############################################################################################################
def apply(freq):
global currentFrequency
global currentPeriod
freq = float(freq)
# Wenn die Frequenz = -1 ist, dann die ausgewählte Frequnz nehmen
if freq == -1.0: freq = selectedFrequency
# Wenn die Frequenz größer als das Maximum ist, setzte sie zurrück
if freq > frequencySettings["top"]: freq = frequencySettings["top"]
# Wenn die Frequenz kleiner als das Minimum ist, setzte sie zurück
if freq < frequencySettings["bottom"]: freq = frequencySettings["bottom"]
print("Wende die Frequenz {}Hz an...".format(freq))
currentFrequency = freq
currentPeriod = 1000 / currentFrequency
updateFreqencyLabel()
#############################################################################################################
# Das Fenster erstellen
root = tkinter.Tk()
root.title("Sound Generator")
root.geometry("640x480")
# Ein Label erstellen, auf dem die aktuelle, die ausgewählte und die maximal mögliche Frequenz angezeigt wird
def updateFreqencyLabel():
text = """
Aktuelle Frequenz: {}hz
Aktuelle Periodenlänge: {}ms
Ausgewählte Frequenz: {}hz
Ausgewählte Periodenlänge: {}ms
Maximal mögliche Frequenz: {}hz
Maximal mögliche Periodenlänge: {}ms
Minimal mögliche Frequenz: {}hz
Minimal mögliche Periodenlänge: {}ms
""".format(
currentFrequency,
round(currentPeriod, 1),
selectedFrequency,
round(selectedPeriod, 1),
frequencySettings["top"],
round(1000 / frequencySettings["top"], 1),
frequencySettings["bottom"],
round(1000 / frequencySettings["bottom"], 1)
)
rootLabelFreqency.config(text=text)
rootLabelFreqency = tkinter.Label(
root,
text=""
)
rootLabelFreqency.pack()
updateFreqencyLabel()
# Einen Slider erstellen, auf dem die Frequenz eingestellt werden kann
def onSliderChange(val):
global selectedFrequency
global selectedPeriod
# Berechne die ausgewählte Frequenz
selectedFrequency = float(val)
selectedPeriod = 1000 / selectedFrequency
updateFreqencyLabel()
rootSliderFrequency = tkinter.Scale(root,
from_=frequencySettings["bottom"],
to=frequencySettings["top"],
orient=tkinter.HORIZONTAL,
command = onSliderChange,
tickinterval=10,
length=640
)
rootSliderFrequency.pack()
# Einen Knopf mit dem die ausgewählte Frequenz angeweendet werden kann, ein Knopf mit dem 50 Hz angeweendet werden kann, ein Knopf mit dem die Frequenz auf 60hz zurückgesetzt werden kann
rootButtonApply = tkinter.Button(
root,
text="Ausgewählte Frequenz anwenden",
command=lambda: apply(-1.0)
)
rootButton50hz = tkinter.Button(
root,
text="50 Hz anwenden",
command=lambda: apply(50.0)
)
rootButtonReset = tkinter.Button(
root,
text="60 Hz anwenden (Zurrücksetzen)",
command=lambda: apply(60.0)
)
rootButtonApply.pack()
rootButton50hz.pack()
rootButtonReset.pack()
# Das Fenster anzeigen und auf den Benutzer warten
tkinter.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment