I am trying to create a program that plays sound and shows the wave. However, when I try to call the multiprocessing.Process
method so that I can cancel the playback if the user clicks the play button before the sound has finished. However, instead of calling my actualPlaySound
method, it seems to recall my code and another tkinter
window opens. Please help!
from tkinter import *
import math, time, threading, winsound, os, multiprocessing
def update ():
global modded
if not modded:
modded = True
stringAmplitude.set (str (amplitude.get ()))
stringFrequency.set (str (frequency.get ()))
modded = False
c.delete (ALL)
width, height = c.winfo_width (), c.winfo_height () / 2
freq = frequency.get ()
c.create_line (0, 25, width, 25)
c.create_polygon (15, 10, 0, 25, 15, 40)
c.create_polygon (width - 15, 10, width, 25, width - 15, 40)
if freq <= 100: c.create_text (width / 2, 15, text = "1 second")
elif freq <= 1000:
c.create_text (width / 2, 15, text = "10 milliseconds")
freq = freq / 100
else:
c.create_text (width / 2, 15, text = "1 millisecond")
freq = freq / 1000
ampl, freq = amplitude.get () ** 0.5, freq * math.pi * 2
for x in range (width):
c.create_line (x, math.sin (x * freq / width) * ampl * (height - 30 if height > 30 else 0) / 10 + (height if height > 35 else 35), x + 1, math.sin ((x + 1) * freq / width) * ampl * (height - 30 if height > 30 else 0) / 10 + (height if height > 35 else 35))
def stringUpdate ():
global modded
if not modded:
modded = True
try: amplitude.set (float (stringAmplitude.get ()))
except: pass
try: frequency.set (float (stringFrequency.get ()))
except: pass
modded = False
def playSound ():
global p
if not p or not p.is_alive ():
p = multiprocessing.Process (target = actualPlaySound)
p.start ()
else: p.terminate ()
def actualPlaySound ():
freq = int (frequency.get ())
if freq < 37:
l.config (text = "Too low!")
elif freq > 32767:
l.config (text = "Too high!")
else:
l.config (text = "Playing...")
winsound.Beep (freq, 5000)
l.config (text = "Played!")
modded, p = False, None
root = Tk ()
root.title ("Waves")
amplitude, frequency, stringAmplitude, stringFrequency = DoubleVar (), DoubleVar (), StringVar (), StringVar ()
amplitude.set (50)
frequency.set (1000)
stringAmplitude.set ("50")
stringFrequency.set ("1000")
amplitude.trace ("w", lambda a, b, c: update ())
frequency.trace ("w", lambda a, b, c: update ())
stringAmplitude.trace ("w", lambda a, b, c: stringUpdate ())
stringFrequency.trace ("w", lambda a, b, c: stringUpdate ())
root.bind ("<Configure>", lambda event: update ())
Label (root, text = "Frequency").grid (row = 0, column = 0)
Scale (root, from_ = 50, to = 32000, orient = "horizontal", variable = frequency).grid (row = 1, column = 0)
Entry (root, textvariable = stringFrequency).grid (row = 2, column = 0)
Frame (root, height = 50).grid (row = 3, column = 0)
Label (root, text = "Amplitude (this doesn't\nchange playback volume)").grid (row = 4, column = 0)
Scale (root, orient = "horizontal", variable = amplitude).grid (row = 5, column = 0)
Entry (root, textvariable = stringAmplitude).grid (row = 6, column = 0)
l = Label (root, text = "Ready to go!")
l.grid (row = 7, column = 0)
Button (root, text = "Play", command = lambda: threading.Thread (target = playSound).start ()).grid (row = 8, column = 0)
c = Canvas (root, bg = "white", width = 500, height = 400)
c.grid (row = 0, column = 1, rowspan = 20, sticky = "nsew")
Grid.columnconfigure (root, 1, weight = 1)
for y in range (20): Grid.rowconfigure (root, y, weight = 1)
update ()
root.mainloop ()
os._exit (0)