Search code examples
pythonbuttontkintercrashpyaudio

Tkinter button calling function to play wave with PyAudio -- crashes


As soon as I hit the button, it stays pressed, and the program crashes. The sound does play though. I'm using code straight form the PyAudio site so I'm a little confused here why it crashes.

from tkinter import *
import pyaudio
import wave
import sys

root = Tk()
root.title("Compose-O-Matic")
root.geometry("400x300")

def play_audio():
    chunk = 1024
    wf = wave.open('misc_environment3.wav', 'rb')
    p = pyaudio.PyAudio()

    stream = p.open(
        format = p.get_format_from_width(wf.getsampwidth()),
        channels = wf.getnchannels(),
        rate = wf.getframerate(),
        output = True)

    data = wf.readframes(chunk)

    while data != '':
        stream.write(data)
        data = wf.readframes(chunk)

    stream.stop_stream()
    stream.close()
    p.terminate()

app = Frame(root)
app.grid()

button_start = Button(app, text = ">", command = play_audio)
button_start.grid()

root.mainloop()

Solution

  • Use threading to play music.

    from tkinter import *
    import pyaudio
    import wave
    import sys
    import threading
    
    # --- classes ---
    
    def play_audio():
        global is_playing
        chunk = 1024
        wf = wave.open('misc_environment3.wav', 'rb')
        p = pyaudio.PyAudio()
    
        stream = p.open(
            format = p.get_format_from_width(wf.getsampwidth()),
            channels = wf.getnchannels(),
            rate = wf.getframerate(),
            output = True)
    
        data = wf.readframes(chunk)
    
        while data != '' and is_playing: # is_playing to stop playing
            stream.write(data)
            data = wf.readframes(chunk)
    
        stream.stop_stream()
        stream.close()
        p.terminate()
    
    # --- functions ---
    
    def press_button_play():
        global is_playing
        global my_thread
    
        if not is_playing:
            is_playing = True
            my_thread = threading.Thread(target=play_audio)
            my_thread.start()
    
    def press_button_stop():
        global is_playing
        global my_thread
    
        if is_playing:
            is_playing = False
            my_thread.join()
    
    # --- main ---
    
    is_playing = False
    my_thread = None
    
    root = Tk()
    root.title("Compose-O-Matic")
    root.geometry("400x300")
    
    button_start = Button(root, text="PLAY", command=press_button_play)
    button_start.grid()
    
    button_stop = Button(root, text="STOP", command=press_button_stop)
    button_stop.grid()
    
    root.mainloop()