You need to enable JavaScript to run this app. 如何从QAudioInput实时采集音频存为NumPy数组并传入SciPy FFT
优惠活动
大模型
产品
解决方案
定价
更多

如何从QAudioInput实时采集音频存为NumPy数组并传入SciPy FFT

实现方案

你原有代码报错的核心原因是调用QByteArray.toUInt()是尝试将整段二进制音频数据转换为单个无符号整数,而你的需求是把每个采样点对应一个数值、组成数组,所以转换逻辑完全不对。

完整可运行实现代码

from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtMultimedia import QAudioDeviceInfo, QAudioFormat, QAudioInput
import numpy as np
from scipy.fft import fft, fftfreq
import sys

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        info = QAudioDeviceInfo()
        input_device = info.defaultInputDevice()
        if input_device.isNull():
            print("There is no audio input device available.")
            exit(-1)

        audio_format = QAudioFormat()
        audio_format.setSampleRate(44100)
        audio_format.setSampleSize(8)
        audio_format.setChannelCount(1)
        audio_format.setCodec("audio/pcm")
        audio_format.setSampleType(QAudioFormat.UnSignedInt)

        if sys.byteorder == "little":
            audio_format.setByteOrder(QAudioFormat.LittleEndian)
        else:
            audio_format.setByteOrder(QAudioFormat.BigEndian)
        # 可选:设置音频缓冲区大小,控制每次回调的音频长度
        self.audioInput = QAudioInput(input_device, audio_format, self)
        self.ioDevice = self.audioInput.start()
        self.ioDevice.readyRead.connect(self.read_audio)

    def read_audio(self):
        # 读取原始二进制音频数据
        data = self.ioDevice.readAll()
        # 转为Python原生bytes类型
        raw_bytes = data.data()
        # 按你设置的音频格式转为numpy数组,这里对应8位无符号整型
        audio_np = np.frombuffer(raw_bytes, dtype=np.uint8)
        # 可选:去除8位无符号采样的直流偏置,0点对齐到128,FFT结果更准确
        audio_np = audio_np - 128

        # 传递给scipy做FFT计算
        if len(audio_np) > 0:
            yf = fft(audio_np)
            xf = fftfreq(len(audio_np), 1 / 44100)
            # 这里可以自行处理FFT结果,示例打印前10个频率点的幅值
            print(np.abs(yf[:10]))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

注意事项和优化点

  • 如果你调整了音频格式参数,只需要同步修改np.frombuffer的dtype即可:比如16位有符号整型对应np.int16,32位浮点对应np.float32,不需要改动其他逻辑
  • 要解决每次读取音频长度不固定导致FFT输出长度变化的问题,可以加一行self.audioInput.setBufferSize(44100 * 2) 固定每次读取2秒的音频数据,保证每次FFT输入长度固定
  • 要减少频谱泄露可以在FFT前加窗:
from scipy.signal import hann
audio_np = audio_np * hann(len(audio_np))

把以上代码插入到计算FFT的代码之前即可。

内容的提问来源于stack exchange,提问作者Jaime02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 21:45:03