待处理的wav文件中包含多个相似的脉冲,要分别保存这些脉冲的完整波形,并使其采样点数量一致。
wav的切割与保存使用wavopen,参考:
(Python) 在Python中对WAV音频文件进行分割与拼接_wav分割-CSDN博客
用循环互相关的方式计算相关性,匹配脉冲信号,参考:
互相关(cross-correlation)及其在Python中的实现 | Dynamics and Python (fanyublog.com)
def correlation(a,v):
nom = np.linalg.norm(a[:])*np.linalg.norm(v[:])
return irfft(rfft(a)*rfft(v[::-1]))/nom
计算互相关需要numpy类型,但发现由于采用waveopen的返回对象为特殊类型,尝试了几个帖子里转换文件类型的方法,发现还是直接使用librosa读取比较方便,且不会影响之后wav文件的保存。参考的帖子:
Python:将wav文件写入numpy浮动数组-腾讯云开发者社区-腾讯云 (tencent.com)
定位相关性最好的位置:
scipy使用python寻找时间序列的极大值(局部最大值)或极小值(局部最小值),极值点_argrelextrema scipy-CSDN博客
也可参考:Python常用的峰值查找算法整理(peak detection) - 知乎 (zhihu.com)
汇总为
import wave
import numpy as np
from scipy import signal
from scipy.fftpack import rfft,irfft
import librosa
def correlation(a,v):
nom = np.linalg.norm(a[:])*np.linalg.norm(v[:])
return irfft(rfft(a)*rfft(v[::-1]))/nom
def cutwav(wavpath,wav_std):
#wavpath是待处理wav的路径,wav_std是用于计算相关性的参考信号,读入为np数组
wf = wave.open(wavpath, "rb")
# 获取音频文件基本信息
nchannels = wf.getnchannels() # 声道数
sampwidth = wf.getsampwidth() # 采样位宽
framerate = wf.getframerate() # 采样率
nframes = wf.getnframes() # 采样点数
wav,sr=librosa.load(wavpath, sr=None, mono=False)
# 设置分割的长度为10ms
length =int( 0.01 * framerate)
CRR = []
for n_frames in range(0,nframes-length+1):
data=wav[n_frames:n_frames+length]
#print(len(data))
crr=correlation(data,wav_std)
CRR.append(max(crr))
CRR=np.array(CRR)
n_frames=signal.argrelextrema(CRR, np.greater, order=200)#返回对象<class 'numpy.ndarray'>,包含多个属性(array([ 73, 484, 920, 1302], dtype=int64),)。order的大小要根据脉冲的长度调整,不设置order会导致python进入未响应状态
n_frames=n_frames[0]#第一个属性即np数组,得到各极值点的横坐标
for i in range(0,len(n_frames)):
print(n_frames[i])
# 截取片段
wf.setpos(n_frames[i])#将文件指针设置到指定位置。
data = wf.readframes(length)
# 保存为新文件
new_wf = wave.open("wav_%03d.wav" % (i), "wb")
new_wf.setnchannels(nchannels)
new_wf.setsampwidth(sampwidth)
new_wf.setframerate(framerate)
new_wf.writeframes(data)
new_wf.close()
另外,几种wav读取方法应根据需求选择,可参考:
七种python读取语音文件的方法 - glowwormss - 博客园 (cnblogs.com)
Python 读取wav文件的几种方式及优缺点_wav.read-CSDN博客