Почему мой tkinter GUI зависает при попытке остановить поток pyaudio? - PullRequest
0 голосов
/ 11 января 2020

Я пытаюсь сделать аудиоплеер с движущимся курсором. Я хочу иметь возможность изменить звук, прекратить воспроизведение, перемещая курсор, нажимая.

Прямо сейчас, пока он играет, я могу перемещать курсор, взаимодействовать с другими кнопками на GUI (просмотрите файл et c.). Я могу воспроизвести его снова или выйти из программы ПОСЛЕ окончания звукового потока. Проблема в том, что когда я пытаюсь остановить потоковую передачу или выйти из нее, программа останавливается.

Я нашел этот пример, где для потоковой передачи используется многопроцессорная обработка. Я видел другие примеры с потоками тоже. Но, поскольку я могу взаимодействовать с GUI во время потоковой передачи, я подумал, что тоже смогу остановить поток без проблем. Это правильно? Если мне нужно использовать многопоточность, могу ли я избежать инициализации потока каждый раз, когда я играю?

Я проверил этот тоже для блиттинга и событий, но нет функции остановки.

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pyaudio
import wave
import tkinter as tk
from tkinter import * 
from tkinter import filedialog as tkFileDialog
from tkinter import messagebox as tkMessageBox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.backend_bases import Event

class myGUI:
    def __init__(self,parent):
        self.parent = parent
        self.initUI()

    def initUI(self):

        self.inputFile = '/sounds/mysound.wav'

        self.quitbutton = Button(self.parent, text="Quit", command=self.quit)
        self.quitbutton.grid(row=4,column=4, sticky=W)

        self.play_mode = False
        self.playbutton = Button(self.parent, text="Play", command=self.playsound)
        self.playbutton.grid(row=1, column=0, sticky=W, padx=(750, 6))

        self.p = pyaudio.PyAudio()

        # initialization for plotting
        fig = plt.figure(figsize=(15,2), dpi=100)
        self.a = fig.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(fig, self.parent)
        self.canvaswidget = self.canvas.get_tk_widget()
        self.canvaswidget.grid(row=2,column=0,sticky=W, padx=10)

        toolbarFrame = Frame(master=self.parent)
        toolbarFrame.grid(row=3,column=0)
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, toolbarFrame)
        self.toolbar.update()

        self.canvas._tkcanvas.grid(row=2,column=0,sticky=W, padx=10)
        self.background = self.canvas.copy_from_bbox(self.a.bbox)
        self.cursor = self.a.axvline(color="y", animated=True)
        self.cursor.set_xdata(0)

        cid1 = self.canvas.mpl_connect('playback_move_event', self.playbackMove)
        self.playbackmoveevent = Event('playback_move_event',self)

        self.plot()

    def plot(self):
        self.wf = wave.open(self.inputFile,'rb')
        self.x = np.fromstring(self.wf.readframes(self.wf.getnframes()), dtype=np.int16)
        self.wf.rewind()
        self.a.clear()
        self.a.plot(self.x)
        self.cursor.set_xdata(0)
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.a.bbox)
        self.canvaswidget.focus_set()

    def quit(self):
        try:
            self.stream.stop_stream()
            self.stream.close()
            self.wf.close()
            self.p.terminate()
        except:
            print("no stream to close")
        finally:
            self.parent.destroy()

    def playbackMove(self,event):
        # move cursor by audio chunk size
        self.cursor.set_xdata(self.cursor.get_xdata()+1024)
        self.updateCursor()

    def updateCursor(self):
        self.canvas.restore_region(self.background)
        self.a.draw_artist(self.cursor)
        self.canvas.blit(self.a.bbox)

    def initStream(self): 

        def _callbackstream(in_data, frame_count, time_info, status):
            data = self.wf.readframes(frame_count)
            self.canvas.callbacks.process('playback_move_event',self.playbackmoveevent)
            return (data, pyaudio.paContinue)

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

    def playsound(self):  # play/stop button
        if self.play_mode == True:
            self.playbutton.config(text="Play")
            self.stream.stop_stream()
            self.stream.close()  # tried without closing too
            print("stopping stream")
            self.play_mode = False

        else:
            self.initStream()
            self.play_mode = True
            self.playbutton.config(text="Stop")
            print("starting stream")
            self.stream.start_stream()

root = Tk()
gui = myGUI(root) 
root.mainloop()

Спасибо за ваше время и помощь!

...