用python写一边录音一边播放一边显示FFT波形的三线程pyqt5程序
时间: 2023-10-04 18:14:14 浏览: 149
FFT.zip_fft_fft python_python FFT程序_python fft
以下是一种可能的实现方式:
```python
import pyaudio
import numpy as np
import sys
import threading
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtCore import Qt
class RecordThread(threading.Thread):
def __init__(self):
super().__init__()
self.chunk_size = 1024 # 每次读取的音频数据块大小
self.sample_rate = 44100 # 采样率
self.pa = pyaudio.PyAudio()
self.stream = self.pa.open(format=pyaudio.paInt16,
channels=1,
rate=self.sample_rate,
input=True,
frames_per_buffer=self.chunk_size)
def run(self):
while True:
data = self.stream.read(self.chunk_size)
data_array = np.frombuffer(data, dtype=np.int16)
spectrum = np.abs(np.fft.fft(data_array))[:self.chunk_size // 2]
spectrum /= np.max(spectrum)
spectrum = spectrum[:256]
spectrum_db = 20 * np.log10(spectrum)
spectrum_db = np.clip(spectrum_db, -50, 0)
spectrum_db += 50
spectrum_db /= 50
spectrum_db = spectrum_db[::-1]
# 将处理好的数据传递给UI线程
ui_thread.update_spectrum(spectrum_db)
class PlayThread(threading.Thread):
def __init__(self):
super().__init__()
self.chunk_size = 1024 # 每次播放的音频数据块大小
self.sample_rate = 44100 # 采样率
self.pa = pyaudio.PyAudio()
self.stream = self.pa.open(format=pyaudio.paInt16,
channels=1,
rate=self.sample_rate,
output=True,
frames_per_buffer=self.chunk_size)
def run(self):
while True:
data = np.zeros(self.chunk_size, dtype=np.int16)
self.stream.write(data)
class UiThread(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Real-time FFT')
self.setGeometry(200, 200, 800, 600)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.layout = QVBoxLayout()
self.widget.setLayout(self.layout)
self.spectrum = np.zeros(256) # 初始化频谱数据
self.setMinimumWidth(600)
self.setMinimumHeight(400)
def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(QPen(Qt.blue, 2))
width = self.width()
height = self.height()
bar_width = width / len(self.spectrum)
for i, value in enumerate(self.spectrum):
x = i * bar_width
y = height * (1 - value)
painter.drawLine(x, height, x, y)
def update_spectrum(self, spectrum):
self.spectrum = spectrum
self.update()
if __name__ == '__main__':
app = QApplication(sys.argv)
ui_thread = UiThread()
record_thread = RecordThread()
play_thread = PlayThread()
ui_thread.show()
record_thread.start()
play_thread.start()
sys.exit(app.exec_())
```
这个程序中有三个线程:
- RecordThread:负责实时录音并进行FFT变换,将处理好的频谱数据传递给UI线程。
- PlayThread:负责实时播放静音,以保持麦克风始终处于工作状态。
- UiThread:负责显示频谱数据,并在接收到RecordThread传递的数据时更新界面。
在主函数中,先创建一个Qt应用程序,然后创建UiThread、RecordThread和PlayThread三个线程,并启动它们。最后进入应用程序的事件循环,等待用户关闭程序。
阅读全文