用python写一边录音一边播放一边显示FFT波形pyqt5多线程的程序
时间: 2023-10-04 18:14:04 浏览: 240
由于录音和播放都需要使用麦克风和扬声器,所以需要使用PyAudio库来实现。同时,为了实现多线程,需要使用QtCore模块中的QThread类。
以下是一个简单的示例程序,能够同时进行录音、播放和显示FFT波形:
```python
import sys
import numpy as np
import pyaudio
import wave
from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.qt_compat import QtWidgets as MplWidget
from matplotlib.figure import Figure
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
WAVE_OUTPUT_FILENAME = "output.wav"
class RecorderThread(QtCore.QThread):
def __init__(self):
super().__init__()
self.frames = []
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
def run(self):
while True:
data = self.stream.read(CHUNK)
self.frames.append(data)
def stop(self):
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
class PlayerThread(QtCore.QThread):
def __init__(self):
super().__init__()
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True,
frames_per_buffer=CHUNK)
def run(self):
while True:
if len(recorder_thread.frames) > 0:
data = recorder_thread.frames.pop(0)
self.stream.write(data)
def stop(self):
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
class FFTPlotWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.figure = Figure()
self.canvas = MplWidget(self.figure)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.canvas)
self.setLayout(layout)
self.ax = self.figure.add_subplot(111)
self.ax.set_xlim(0, RATE/2)
self.ax.set_ylim(0, 100)
self.ax.set_xlabel('Frequency (Hz)')
self.ax.set_ylabel('Amplitude')
self.line, = self.ax.plot([], [])
def update(self):
if len(recorder_thread.frames) > 0:
data = b''.join(recorder_thread.frames)
y = np.frombuffer(data, dtype=np.int16)
yf = np.fft.rfft(y)
xf = np.linspace(0, RATE/2, len(yf))
self.line.set_data(xf, np.abs(yf))
self.canvas.draw()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.recording = False
self.playing = False
self.recorder_thread = RecorderThread()
self.player_thread = PlayerThread()
self.fft_plot_widget = FFTPlotWidget()
self.setCentralWidget(self.fft_plot_widget)
self.start_button = QtWidgets.QPushButton('Start')
self.start_button.clicked.connect(self.start_recording)
self.stop_button = QtWidgets.QPushButton('Stop')
self.stop_button.clicked.connect(self.stop_recording)
self.toolbar = self.addToolBar('Toolbar')
self.toolbar.addWidget(self.start_button)
self.toolbar.addWidget(self.stop_button)
self.show()
def start_recording(self):
self.recording = True
self.playing = True
self.recorder_thread.start()
self.player_thread.start()
def stop_recording(self):
self.recording = False
self.playing = False
self.recorder_thread.stop()
self.player_thread.stop()
def update_fft_plot(self):
self.fft_plot_widget.update()
app = QtWidgets.QApplication(sys.argv)
main_window = MainWindow()
timer = QtCore.QTimer()
timer.timeout.connect(main_window.update_fft_plot)
timer.start(50)
sys.exit(app.exec_())
```
该程序使用了三个线程,分别用于录音、播放和更新FFT波形图。其中,录音和播放线程都是无限循环,不断从麦克风读取音频数据和向扬声器写入音频数据。更新FFT波形图的线程使用了Qt的定时器,每隔一定时间就更新一次FFT波形图。
FFT波形图的显示使用了matplotlib库。在FFTPlotWidget类中,定义了一个Figure对象和一个Axes对象,用于绘制FFT波形图。update方法会在每次定时器触发时被调用,从录音线程中获取音频数据,计算FFT并更新图形。
程序界面中只有两个按钮,分别用于开始录音和停止录音。通过点击这两个按钮可以控制录音的开始和结束。在录音过程中,程序会自动播放录制的音频数据,并且实时地显示FFT波形图。
阅读全文