PyQt6+PyAudio录音异常:点击按钮生成0时长WAV文件
解决PyQt6+PyAudio录音生成0秒音频的问题
你的代码能正常显示界面和更新状态,但生成的音频文件时长为0秒,核心原因是没有在录音过程中读取音频数据并存储到frames列表,同时存在几处小问题需要修正:
问题分析
- 录音流程缺失:打开音频流后,没有循环读取音频块数据到
self.frames,导致最终写入文件时没有有效数据。 - 重复初始化PyAudio:每次点击录音按钮都重新创建
PyAudio实例,会造成资源浪费和潜在的冲突。 - 主程序入口笔误:
if __name__ == 'main':应为if __name__ == '__main__':,否则程序可能无法正确启动(你当前能运行可能是IDLE的特殊处理,但这是标准错误)。 - UI阻塞风险:如果直接在主线程循环读取音频数据,会导致界面卡死,需要用线程来处理录音逻辑。
修复后的完整代码
import sys import wave from PyQt6.QtCore import QTimer, QThread, pyqtSignal import pyaudio from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QWidget, QGridLayout class RecorderThread(QThread): finished = pyqtSignal() def __init__(self, p, chunk, sample_format, channels, fs, frames): super().__init__() self.p = p self.chunk = chunk self.sample_format = sample_format self.channels = channels self.fs = fs self.frames = frames self.is_recording = True def run(self): # 打开音频流 stream = self.p.open(format=self.sample_format, channels=self.channels, rate=self.fs, frames_per_buffer=self.chunk, input=True) # 循环读取音频数据直到停止 while self.is_recording: data = stream.read(self.chunk) self.frames.append(data) # 停止并关闭流 stream.stop_stream() stream.close() self.finished.emit() class RecordingWindow(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.chunk = 1024 self.sample_format = pyaudio.paInt16 self.channels = 1 self.fs = 44100 self.seconds = 3 self.filename = "new.wav" self.p = pyaudio.PyAudio() self.recorder_thread = None def init_ui(self): self.setWindowTitle("Audio Recorder") self.setGeometry(100, 100, 400, 300) self.status_label = QLabel("Press 'Record' to start recording.\nMicrophone will record for three seconds.", self) self.record_button = QPushButton("Record", self) self.record_button.clicked.connect(self.start_recording) layout = QGridLayout() layout.addWidget(self.status_label, 0, 0, 2, 2) layout.addWidget(self.record_button, 2, 0, 1, 2) # 调整布局避免控件重叠 central_widget = QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) def start_recording(self): self.status_label.setText("Recording... Please Speak Loudly!") self.record_button.setEnabled(False) self.frames = [] # 创建并启动录音线程 self.recorder_thread = RecorderThread(self.p, self.chunk, self.sample_format, self.channels, self.fs, self.frames) self.recorder_thread.finished.connect(self.stop_recording) self.recorder_thread.start() # 启动定时器,指定时间后停止录音 self.timer = QTimer() self.timer.timeout.connect(self.stop_recording_thread) self.timer.start(self.seconds * 1000) def stop_recording_thread(self): # 停止线程的录音循环 if self.recorder_thread and self.recorder_thread.is_recording: self.recorder_thread.is_recording = False self.timer.stop() def stop_recording(self): # 等待线程结束 if self.recorder_thread: self.recorder_thread.wait() self.recorder_thread = None # 写入音频文件 wf = wave.open(self.filename, 'wb') wf.setnchannels(self.channels) wf.setsampwidth(self.p.get_sample_size(self.sample_format)) wf.setframerate(self.fs) wf.writeframes(b''.join(self.frames)) wf.close() self.status_label.setText("Recording completed. Press 'Record' to record again.") self.record_button.setEnabled(True) def closeEvent(self, event): # 关闭前清理资源 if self.recorder_thread and self.recorder_thread.isRunning(): self.recorder_thread.is_recording = False self.recorder_thread.wait() if hasattr(self, 'p'): self.p.terminate() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) window = RecordingWindow() window.show() sys.exit(app.exec())
关键修改说明
- 新增录音线程:创建
RecorderThread类处理音频读取逻辑,避免阻塞UI主线程,保证界面响应正常。 - 补充音频读取循环:在线程的
run方法中循环读取音频块并添加到frames列表,确保录音数据被正确存储。 - 修正PyAudio初始化:仅在窗口初始化时创建一次
PyAudio实例,避免重复初始化导致的资源问题。 - 修复主程序入口:将
if __name__ == 'main':改为标准的if __name__ == '__main__':。 - 完善资源清理:在窗口关闭时确保线程停止并释放PyAudio资源,避免内存泄漏。
macOS额外注意事项
确保你的Python程序已经获得麦克风权限:
- 打开「系统设置」→「隐私与安全性」→「麦克风」,确认VSCode或IDLE已被授予权限。
内容的提问来源于stack exchange,提问作者finceth
相关产品推荐
相关产品推荐

