最近在阅读语音方向的论文,其中有个被提及很多的语音信号特征MFCC(Mel-Frequency Cepstral Coefficients),找到了基于python的语音库librosa(version=0.7.1)和python_speech_features(version=0.6),下文对这两个库计算MFCC的流程细节稍作梳理。LibROSA - librosa 0.7.1 documentationlibrosa.github.iopython_speech_featurespypi.org
一、librosa
1.源语音信号,shape = wav.length
wav, sample_rate = librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None,
dtype=np.float32, res_type='kaiser_best') #加载语音文件得到原始数据
2.填充及分帧(无预加重处理),分帧后所有帧的shape = n_ftt * n_frames
y = numpy.pad(array, pad_width, mode, **kwargs) # 原函数及参数
y = numpy.pad(wav, int(n_fft // 2), mode='reflect') # 默认,n_fft 为傅里叶变换维度
y = numpy.pad(wav, (0,pad_need), mode='constant') # 自定义
librosa调用numpy对源语音数据进行填充,默认模式是'reflect'进行镜像填充,举个例子:
对序列[1,2,3,4,5]进行左填充2个、右填充3个,左边以1作对称轴填充[3,2],右边以5作对称轴填充[4,3,2],最后结果为[3,2,1,2,3,4,5,4,3,2]。
自定义模式是按照python_speech_features的方式设置参数的,pad_need是经过计算得到的需要填充的数据数量,在下文说明。
y_frames = util.frame(y, frame_length=n_fft, hop_length=hop_length) # hop_length为帧移,librosa中默认取窗长的四分之一
一般来说 帧长 = 窗长 = 傅里叶变换维度,否则要进行填充或者截断处理。通过阅读源码发现,librosa调用的分帧方式和python_speech_features一样,这和librosa.feature.melspectrogram()参数里的center描述有所冲突,我把两者对同一语音文件的分帧结果输出到excel文件进行了对比,结果是一样的,当然分帧之前的填充方式也修改成了一致。
3.对所有帧进行加窗,shape = n_ftt * n_frames。librosa中window.shape = n_ftt * 1
fft_window = librosa.filters.get_window(window, Nx, fftbins=True) # 原函数及参数
fft_window = get_window('hann', win_length, fftbins=True) # 窗长一般等于傅里叶变换维度,短则填充长则截断
librosa加的窗函数调用的scipy,如scipy.signal.windows.hann。python_speech_features加的窗函数调用的numpy,如numpy.hanning,汉宁窗公式为:
给原信号加窗的实现方式为相乘:
frames *= 0.5 - 0.5 * numpy.cos((2 * numpy.pi * n) / (frame_length - 1)) # 原信号乘以汉宁窗函数
4.STFT处理得到spectrum(频谱,实际是多帧的),shape = (n_ftt // 2 +1) * n_frames
fft = librosa.core.fft.get_fftlib()
stft_matrix = fft