PyAudio播放Int16格式正弦波无声音问题排查咨询
问题背景
正在开发一款支持通过TCP接收音频、实时播放并存储为文件的音频流播放器,当前仅完成播放器模块开发,遇到音频播放异常问题,已排查到的现象如下:
- PyAudio无法正常播放生成的正弦波音频
- 使用sounddevice播放原始浮点格式正弦波可正常出声,说明源数据本身无逻辑错误
- 使用sounddevice播放经转换得到的Int16格式数据时同样播放失败,初步推测问题出在格式转换环节
- 若将音频数据格式与PyAudio流配置修改为float32,即可正常播放,暂不清楚该现象产生原因
问题复现代码
import numpy as np import pyaudio import sounddevice as sd from array import array import wave sample_rate = 44100 Fs = 50000 f = 5000 sample = 150000 def play_stream(ob): "converting object to pyauido required format" tone = ob.astype(np.int16) bytestream = tone.tobytes() "playing data with pyaudio" p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paInt16, channels=1, rate=sample_rate, output=True) if len(bytestream)>0: stream.write(bytestream) else: print("no data!") stream.stop_stream() stream.close() print("* stream finished") p.terminate() "testing data in alternate method" sd.play(ob, 44100) print ("play finished!") "generating sine wave" x = np.arange(sample) ob = np.sin(2 * np.pi * f * x /Fs) "playing sine wave" play_stream(ob)
根因分析
问题出在两个核心位置:
- Int16格式转换逻辑错误:
np.sin()生成的正弦波数据是取值范围为[-1.0, 1.0]的浮点类型数据,而Int16格式音频的有效取值范围是[-32768, 32767]。直接调用astype(np.int16)做类型强转时,浮点数会被直接截断取整,所有绝对值小于1的采样点都会被转为0,最终得到的字节流几乎全是静音数据,自然无法正常播放。这也是float32格式能正常播放的核心原因——float32格式的音频本身就要求采样值在[-1.0, 1.0]区间,不需要做幅值缩放。 - 采样率配置不匹配:生成正弦波时使用的采样率
Fs=50000,但PyAudio和sounddevice播放时配置的采样率是44100,即使格式转换正确,播放出来的音调也会和预期不符。
修复方案
- 修正Int16转换逻辑:先将浮点采样值缩放到Int16的取值区间,再加截断防止溢出,最后转类型,代码如下:
# 原错误写法:直接强转导致采样值几乎全为0 # tone = ob.astype(np.int16) # 正确写法:幅值缩放+截断防溢出+类型转换 tone = (ob * 32767).clip(-32768, 32767).astype(np.int16) bytestream = tone.tobytes() - 统一采样率配置:将生成正弦波的采样率
Fs和播放配置的sample_rate设为相同值,比如统一为44100,避免播放音调异常。 - 验证sounddevice Int16播放:使用上述正确转换得到的Int16数据调用sounddevice播放时,需要额外指定dtype为
int16,即调用sd.play(tone, 44100, dtype='int16')即可正常出声。
内容的提问来源于stack exchange,提问作者Mai r
相关产品推荐
相关产品推荐

