如何用Matplotlib渲染具有正确音量水平的音频波形图?
修复Matplotlib生成音频波形图的电平与截断问题
问题说明
以下为同一音频文件的波形对比:
- 左侧:正确的原始未归一化音频波形
- 右侧:Matplotlib生成的存在问题的波形
需要解决两个核心问题:
- 修正音频电平的显示精度
- 解决Y轴高度截断问题
- Y轴上下存在无意义的空白间隙
- 测试不同采样率的归一化文件后发现,无论音频电平如何,间隙都会出现
原使用代码
import numpy as np import wave, sys, os import matplotlib.pyplot as plt File_Name = os.path.basename(sys.argv[1]) plt.rcParams["axes.xmargin"] = 0 #-=-=-=-# try: Audio = wave.open(sys.argv[1], "r") except Exception: raise SystemExit("WAV format not integer, exiting.") if Audio.getnchannels() > 1: raise SystemExit("Not a mono file, exiting.") Signal = Audio.readframes(-1) Signal = np.fromstring(Signal, "int16") Time = np.linspace(0, len(Signal) / Audio.getframerate(), num = len(Signal)) #-=-=-=-# plt.plot(Time, Signal, color = "#000000") #plt.axis("off") #plt.savefig(os.path.splitext(File_Name)[0] + ".png", # bbox_inches = "tight", transparent = 1, pad_inches = 0 #) plt.show()
问题根源与解决方案
问题1:音频电平显示偏差
int16格式的WAV音频信号取值范围为**-32768 ~ 32767**,Matplotlib默认Y轴会自动缩放并留有余量,导致电平显示不匹配原始信号幅度。
问题2:Y轴空白间隙
Matplotlib的plot方法默认会为Y轴添加5%左右的padding,即使数据已经占满理论范围,也会出现上下空白。
修改后的代码
import numpy as np import wave, sys, os import matplotlib.pyplot as plt File_Name = os.path.basename(sys.argv[1]) plt.rcParams["axes.xmargin"] = 0 try: Audio = wave.open(sys.argv[1], "r") except Exception: raise SystemExit("WAV格式非整数类型,程序退出。") if Audio.getnchannels() > 1: raise SystemExit("不是单声道文件,程序退出。") Signal = Audio.readframes(-1) # 替换已废弃的np.fromstring,使用更规范的np.frombuffer Signal = np.frombuffer(Signal, dtype=np.int16) Time = np.linspace(0, len(Signal) / Audio.getframerate(), num=len(Signal)) plt.plot(Time, Signal, color="#000000") # 强制Y轴覆盖int16音频的完整取值范围,消除间隙并修正电平 plt.ylim(-32768, 32767) # 若需将电平归一化到-1~1范围,取消以下两行注释 # Signal_normalized = Signal / 32767.0 # plt.ylim(-1, 1) # plt.axis("off") # plt.savefig(os.path.splitext(File_Name)[0] + ".png", # bbox_inches="tight", transparent=True, pad_inches=0 # ) plt.show()
关键修改点
- 替换废弃API:用
np.frombuffer替代np.fromstring,后者在NumPy 1.16+版本已被标记为废弃,前者更安全且符合现代NumPy规范 - 锁定Y轴范围:通过
plt.ylim(-32768, 32767)强制Y轴覆盖int16信号的完整取值范围,彻底消除上下空白间隙,同时让电平显示完全匹配原始信号 - 可选归一化:如果需要标准化电平到-1~1范围,只需将信号除以32767.0并设置对应的Y轴极限即可
内容的提问来源于stack exchange,提问作者kubinka0505
相关产品推荐
相关产品推荐

