用python生成一边录音一边播放一边显示FFT画布PyQt5的多线程程序
时间: 2023-09-04 18:15:57 浏览: 186
以下是一个使用Python和PyQt5库生成一边录音一边播放一边显示FFT画布的多线程程序:
```
import sys
import numpy as np
import pyaudio
import threading
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtWidgets import QApplication, QWidget
class AudioThread(QThread):
def __init__(self):
super().__init__()
self.chunk = 1024
self.format = pyaudio.paInt16
self.channels = 1
self.rate = 44100
self.p = pyaudio.PyAudio()
self.stream = self.p.open(
format=self.format,
channels=self.channels,
rate=self.rate,
input=True,
output=True,
frames_per_buffer=self.chunk
)
self.frames = []
self.is_running = True
def run(self):
while self.is_running:
data = self.stream.read(self.chunk)
self.frames.append(data)
self.stream.write(data)
def stop(self):
self.is_running = False
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
class FFTThread(QThread):
signal = pyqtSignal(np.ndarray)
def __init__(self, audio_thread):
super().__init__()
self.audio_thread = audio_thread
def run(self):
while self.audio_thread.is_running:
if len(self.audio_thread.frames) > 0:
data = b''.join(self.audio_thread.frames)
self.audio_thread.frames = []
y = np.frombuffer(data, dtype=np.int16)
fft_data = np.abs(np.fft.fft(y))[:len(y) // 2]
self.signal.emit(fft_data)
class FFTWidget(QWidget):
def __init__(self):
super().__init__()
self.fft_data = np.zeros(1024)
self.fft_thread = FFTThread(audio_thread)
self.fft_thread.signal.connect(self.update_fft_data)
self.fft_thread.start()
def update_fft_data(self, fft_data):
self.fft_data = fft_data
def paintEvent(self, event):
qp = QPainter()
qp.begin(self)
qp.setPen(QPen(Qt.white, 2))
width, height = self.width(), self.height()
step = width / len(self.fft_data)
for i, y in enumerate(self.fft_data):
x = i * step
qp.drawLine(x, height, x, height - y // 10)
qp.end()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('Audio FFT')
self.setGeometry(100, 100, 800, 600)
self.audio_thread = AudioThread()
self.fft_widget = FFTWidget()
self.start_button = QPushButton('Start', self)
self.start_button.setGeometry(10, 10, 100, 30)
self.start_button.clicked.connect(self.start_audio)
self.stop_button = QPushButton('Stop', self)
self.stop_button.setGeometry(120, 10, 100, 30)
self.stop_button.clicked.connect(self.stop_audio)
def start_audio(self):
self.audio_thread.start()
def stop_audio(self):
self.audio_thread.stop()
self.fft_thread.quit()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
```
这个程序创建了一个`AudioThread`类,用于录音并播放声音,并将录音数据存储在一个列表中。然后,创建了一个`FFTThread`类,用于计算FFT并发出信号,以更新FFT数据。最后,创建了一个`FFTWidget`类,用于显示FFT数据。在`MainWindow`类中,创建了两个按钮,一个用于启动录音,另一个用于停止录音。当录音开始时,`AudioThread`对象开始运行,`FFTThread`对象开始运行,并将发出的信号连接到`FFTWidget`对象的`update_fft_data()`方法上,以更新FFT数据。然后,`FFTWidget`对象重新绘制,以显示FFT数据的可视化效果。当录音停止时,`AudioThread`对象和`FFTThread`对象都停止,并退出程序。
阅读全文