You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从PyAudio读取的音频数据中提取低音(低频)信号?

实时音频低频(低音)提取实现方案

前置说明

你当前使用的是固定1024长度的音频块处理,低音通常对应20~200Hz的频率范围,可根据需求调整截止频率。你的原代码中存在两个重复的while循环,逻辑冗余,执行完第一个循环后data已为空,第二个循环不会触发,可直接删除。

实现方案

方案1:FFT频域截取实现(逻辑直观,适合固定块处理场景)

通过短时FFT将音频转换到频域,保留低频分量后逆变换回时域即可得到低音数据:

  1. 提前定义参数和加窗函数,减少频谱泄露
  2. 对每个音频块做FFT变换,高频分量幅值置0
  3. 逆FFT转回时域,格式转换后得到低音数组

代码示例

import numpy as np
import pyaudio
import wave

# 可调整参数
CHUNK = 1024
CUTOFF_FREQ = 200 # 低音截止频率,单位Hz

# 初始化音频读取
wf = wave.open('song.wav', 'rb')
SAMPLE_RATE = wf.getframerate()
CHANNELS = wf.getnchannels()
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=CHANNELS,
                rate=SAMPLE_RATE,
                output=True)

# 计算FFT对应截止频率的索引
cutoff_idx = int(CUTOFF_FREQ * CHUNK / SAMPLE_RATE)
# 生成汉明窗减少频谱泄露
window = np.hamming(CHUNK)

data = wf.readframes(CHUNK)
while len(data) > 0:
    stream.write(data)
    data = wf.readframes(CHUNK)
    if len(data) == 0:
        break
    decoded = np.frombuffer(data, dtype=np.int16)
    
    # 低音提取逻辑
    if CHANNELS == 2:
        # 双声道拆分处理
        decoded = decoded.reshape(-1, 2)
        def extract_bass(sig):
            sig_windowed = sig * window
            fft_sig = np.fft.fft(sig_windowed)
            # 高频分量置0
            fft_sig[cutoff_idx:-cutoff_idx] = 0
            bass_sig = np.fft.ifft(fft_sig).real
            return bass_sig.astype(np.int16)
        left_bass = extract_bass(decoded[:,0])
        right_bass = extract_bass(decoded[:,1])
        bass_decoded = np.column_stack((left_bass, right_bass)).flatten()
    else:
        # 单声道处理
        sig_windowed = decoded * window
        fft_sig = np.fft.fft(sig_windowed)
        fft_sig[cutoff_idx:-cutoff_idx] = 0
        bass_sig = np.fft.ifft(fft_sig).real
        bass_decoded = bass_sig.astype(np.int16)
    
    # bass_decoded 即为提取后的低音数组
    print(bass_decoded)

# 资源释放
stream.stop_stream()
stream.close()
p.terminate()

方案2:IIR低通滤波实现(延迟更低,适合实时流场景)

提前生成巴特沃斯低通滤波器系数,每个音频块直接滤波即可,无块效应,实时性更好:

代码示例(需安装scipy库)

from scipy.signal import butter, lfilter

# 生成低通滤波器系数
def butter_lowpass(cutoff, fs, order=3):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    return b, a

b, a = butter_lowpass(CUTOFF_FREQ, SAMPLE_RATE, order=3)

# 循环内替换提取逻辑即可
# 拿到decoded数组后直接调用:
bass_decoded = lfilter(b, a, decoded).astype(np.int16)

注意事项

  • 若需要单独播放低音,直接将bass_decoded调用.tobytes()方法转换为字节流后写入stream即可
  • 截止频率可根据需求调整,需要更低的低音可降低CUTOFF_FREQ到150Hz,需要保留更多中低频可提高到300Hz
  • 如果是实时麦克风输入流,将wav读取逻辑替换为PyAudio的输入流读取逻辑即可复用上述代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:57:00