[英]Recording audio with pyaudio on a button click and stop recording on another buttonclick
[英]Audio recording with PyQt6 and pyaudio stops working after clicking recording button
我想制作一個帶有錄制和停止按鈕的程序,頂部有一個 label 以顯示它是否仍在錄制或已完成錄制。 我從另一個問題中獲取了基本的記錄代碼結構,我重寫它的方式可能存在錯誤。
現在我的問題是:寡婦正在打開,它看起來像我想要的樣子,但是只要我在“記錄”按鈕后單擊任何內容,程序就會自行掛起(label 更改為“記錄...”) . 有一次我也等了大約 10 分鍾,看看我是不是之前的時間太不耐煩了(這不是問題) ,直到 Windows 說“Python 沒有響應”,因為我點擊了退出按鈕/太多次window。
使用:Python 3.10.1 & VSCode 1.63.2
任何幫助將不勝感激!
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *
import pyaudio as pa
import wave
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Rec Audio")
self.stoped = False
vbox = QVBoxLayout()
self.labelRec = QLabel('')
self.labelRec.setFixedSize(130, 15)
hbox = QHBoxLayout()
self.recbtn = QPushButton('▶ record')
self.recbtn.setFixedSize(90, 30)
self.recbtn.clicked.connect(self.recAudio)
self.stopbtn = QPushButton('▪')
self.stopbtn.setFixedSize(40, 30)
self.stopbtn.clicked.connect(self.stopRec)
hbox.addWidget(self.recbtn)
hbox.addWidget(self.stopbtn)
vbox.addWidget(self.labelRec)
vbox.addLayout(hbox)
self.setLayout(vbox)
def recAudio(self):
audio = pa.PyAudio()
frames = []
stream = audio.open(format=pa.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
self.stoped = False
self.labelRec.setText('◉ recording...')
self.repaint()
while self.stoped == False:
data = stream.read(1024)
frames.append(data)
stream.close()
self.labelRec.setText('recording stopped')
wf = wave.open('test_recording.wav', 'wb')
wf.setnchannels(1)
wf.setsampwidth(audio.get_sample_size(pa.paInt16))
wf.setframerate(44100)
wf.writeframes(b''.join(frames))
wf.close()
def stopRec(self):
self.stoped = True
app = QApplication([])
win = Window()
win.show()
sys.exit(app.exec())
您的解決方案中的問題是由於您在與您的 GUI 相同的線程中錄制音頻。
然后當您的代碼到達錄制部分時:
while self.stoped == False:
data = stream.read(1024)
frames.append(data)
GUI 卡住了,沒有任何幫助,因為 GUI 無法處理其他任何內容。
PyQt 提供了非常好的機制來處理稱為信號和插槽的事件,我建議您閱讀更多有關它的信息。 這不是一個容易的話題,尤其是在開始的時候,所以請耐心等待...
我修改了您之前的代碼並使其按您的意圖工作:
import sys
import wave
import pyaudio as pa
from PyQt6.QtCore import QThread, pyqtSignal, pyqtSlot
from PyQt6.QtWidgets import *
class RecordingThread(QThread):
stopped = False
sig_started = pyqtSignal()
sig_stopped = pyqtSignal()
def __init__(self, target_file):
self.target_file = target_file
super().__init__()
def run(self) -> None:
audio = pa.PyAudio()
frames = []
stream = audio.open(format=pa.paInt16, channels=1, rate=44100, input=True, frames_per_buffer=1024)
self.stopped = False
self.sig_started.emit()
while not self.stopped:
data = stream.read(1024)
frames.append(data)
stream.close()
self.sig_stopped.emit()
wf = wave.open(self.target_file, 'wb')
wf.setnchannels(1)
wf.setsampwidth(audio.get_sample_size(pa.paInt16))
wf.setframerate(44100)
wf.writeframes(b''.join(frames))
wf.close()
@pyqtSlot()
def stop(self):
self.stopped = True
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Rec Audio")
# Create recording thread and attach slots to its signals
self.recording_thread = RecordingThread(target_file='test_recording.wav')
self.recording_thread.sig_started.connect(self.recording_started)
self.recording_thread.sig_stopped.connect(self.recording_stopped)
vbox = QVBoxLayout()
self.labelRec = QLabel('')
self.labelRec.setFixedSize(130, 15)
hbox = QHBoxLayout()
self.recbtn = QPushButton('▶ record')
self.recbtn.setFixedSize(90, 30)
# Connect signal "recbtn.clicked" to the slot "recording_thread.start" of our QThread
# Never connect directly to the run, always to start!
self.recbtn.clicked.connect(self.recording_thread.start)
self.stopbtn = QPushButton('▪')
self.stopbtn.setDisabled(True)
self.stopbtn.setFixedSize(40, 30)
# Connect signal "stopbtn.clicked" to the slot "recording_thread.stop" of our QThread
self.stopbtn.clicked.connect(self.recording_thread.stop)
hbox.addWidget(self.recbtn)
hbox.addWidget(self.stopbtn)
vbox.addWidget(self.labelRec)
vbox.addLayout(hbox)
self.setLayout(vbox)
@pyqtSlot()
def recording_started(self):
"""This slot is called when recording starts"""
self.labelRec.setText('◉ recording...')
self.stopbtn.setDisabled(False)
self.recbtn.setDisabled(True)
@pyqtSlot()
def recording_stopped(self):
"""This slot is called when recording stops"""
self.labelRec.setText('recording stopped')
self.recbtn.setDisabled(False)
self.stopbtn.setDisabled(True)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
app.exec()
不同之處在於我們現在使用 QThread,它將在單獨的線程中運行您的音頻錄制,並使您的 GUI 保持活動狀態。
此 QThread 還附加了兩個信號sig_started
和sig_stopped
。
為了通知我們的 Window 記錄正在進行或停止,我們將這些信號連接到插槽recording_started
和recording_stopped
。
現在應該正確記錄您的文件並將其存儲到文件中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.