【发布时间】:2022-04-22 13:44:01
【问题描述】:
我正在开发一个 GUI,它可以使用 sounddevice 和 soundfile 库录制任意时间的音频。按“ctrl+c”按钮组合停止录制过程。
我正在尝试实现一个带有“开始”和“结束”按钮的 GUI。 “开始”按钮应该调用记录功能,“结束”按钮应该模拟“ctrl+c”事件。我不知道这个事件如何在 python 中实现为函数。 非常感谢实施的想法。
如果你使用windows命令提示符python record.py运行,代码运行正常
record.py如下:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import time
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading
class Ui_MainWindow(object):
def __init__(self):
self.threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton.clicked.connect(self.start_button_func)
self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
self.pushButton_1.setObjectName("pushButton")
self.pushButton_1.clicked.connect(self.end_button_func)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.pushButton_1.setText(_translate("MainWindow", "End"))
def record(self):
self.q = queue.Queue()
self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
try:
# Make sure the file is open before recording begins
with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
with self.s:
# 1 second silence before the recording begins
time.sleep(1)
print('START')
print('#' * 80)
print('press Ctrl+C to stop the recording')
while True:
file.write(self.q.get())
except OSError:
print('The file to be recorded already exists.')
sys.exit(1)
except KeyboardInterrupt:
print('The utterance is recorded.')
def callback(self, indata, frames, time, status):
"""
This function is called for each audio block from the record function.
"""
if status:
print(status, file=sys.stderr)
self.q.put(indata.copy())
def start_button_func(self):
self.worker = mythreading.Worker(self.record)
self.threadpool.start(self.worker)
def end_button_func(self):
print('how to stop?')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
mythreading.py如下:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
self.fn = fn
@pyqtSlot()
def run(self):
self.fn()
【问题讨论】:
-
raise KeyboardInterrupt -
@SuperShoot 你能解释一下吗?我想使用按钮生成'ctrl+c'。根本不会使用键盘。
-
因此您想重新创建
ctrl+c所做的事情(即发送SIGINT)到录制过程。这个答案是否这样做:stackoverflow.com/questions/27356837/…?我建议在子进程中从 Python 运行录制进程,然后您可以根据需要终止。 -
@M.Denis,因为你不能使用子进程(因为记录是在其他地方启动的)或试图终止记录进程,它在 Python 中作为子进程启动(使用
os.kill(pid, signal.SIGINT)如链接的答案)不起作用? -
@M.Denis,我看到您正在使用包
soundfile和sounddevice,在您的问题顶部值得一提,因为我认为可能需要终止这些包。你能不能在这里使用sd.stop()或其他内置方法。否则,您似乎可以在 Windows 中使用CTRL_C_EVENT获取 PID 并杀死:stackoverflow.com/questions/6645713/…