《语音信号处理试验教程》(梁瑞宇等)的代码主要是Matlab实现的,现在Python比较热门,所以把这个项目大部分内容写成了Python实现,大部分是手动写的。使用CSDN博客查看帮助文件:
Python语音基础操作–2.1语音录制,播放,读取
Python语音基础操作–2.2语音编辑
Python语音基础操作–2.3声强与响度
Python语音基础操作–2.4语音信号生成
Python语音基础操作–3.1语音分帧与加窗
Python语音基础操作–3.2短时时域分析
Python语音基础操作–3.3短时频域分析
Python语音基础操作–3.4倒谱分析与MFCC系数
Python语音基础操作–4.1语音端点检测
Python语音基础操作–4.2基音周期检测
Python语音基础操作–4.3共振峰估计
Python语音基础操作–5.1自适应滤波
Python语音基础操作–5.2谱减法
Python语音基础操作–5.4小波分解
Python语音基础操作–6.1PCM编码
Python语音基础操作–6.2LPC编码
Python语音基础操作–6.3ADPCM编码
Python语音基础操作–7.1帧合并
Python语音基础操作–7.2LPC的语音合成
Python语音基础操作–10.1基于动态时间规整(DTW)的孤立字语音识别试验
Python语音基础操作–10.2隐马尔科夫模型的孤立字识别
Python语音基础操作–11.1矢量量化(VQ)的说话人情感识别
Python语音基础操作–11.2基于GMM的说话人识别模型
Python语音基础操作–12.1基于KNN的情感识别
Python语音基础操作–12.2基于神经网络的情感识别
Python语音基础操作–12.3基于支持向量机SVM的语音情感识别
Python语音基础操作–12.4基于LDA,PCA的语音情感识别
代码可在Github上下载:busyyang/python_sound_open
声压是定量描述声波的最基本的物理量,它是由于声扰动产生的逾量压强,是空间位置和时间的函数。由于声压的测量比较易于实现,而且通过声压的测量也可以间接求得质点振速等其他声学参量,因此,声压已成为人们最为普遍采用的定量描述声披性质的物理量。
通常讲的卢压指的是有效声压,即在一定时间间隔内将瞬时声压对时间求方均根值所得。设语音长度度为 T T T, 离散点数为 N N N, 则有效声压的计算公式为
P e = 1 T ∑ n = 1 N x 2 Δ t = 1 N Δ t ∑ n = 1 N x 2 Δ t = 1 N ∑ n = 1 N x 2 P_e=\sqrt{\frac{1}{T}\sum\limits_{n=1}^Nx^2\Delta t}=\sqrt{\frac{1}{N\Delta t}\sum\limits_{n=1}^Nx^2\Delta t}=\sqrt{\frac{1}{N}\sum\limits_{n=1}^Nx^2} Pe=T1n=1∑Nx2Δt=NΔt1n=1∑Nx2Δt=N1n=1∑Nx2
其中 x x x表示采样点。只要保证所取的点数 N N N足够大,即可保证计算的准确性。用于计算声压级值的语音帧长一般为20ms、50ms、100ms、200ms以及500ms。计算的结果是一个序列。
class soundBase:
def __init__(self, path):
self.path = path
def audioread(self, formater='sample'):
"""
读取语音文件
2020-2-26 Jie Y. Init
这里的wavfile.read()函数修改了里面的代码,返回项return fs, data 改为了return fs, data, bit_depth
如果这里报错,可以将wavfile.read()修改。
:param formater: 获取数据的格式,为sample时,数据为float32的,[-1,1],同matlab同名函数. 否则为文件本身的数据格式
指定formater为任意非sample字符串,则返回原始数据。
:return: 语音数据data, 采样率fs,数据位数bits
"""
fs, data, bits = wavfile.read(self.path)
if formater == 'sample':
data = data / (2 ** (bits - 1))
return data, fs, bits
def SPL(self, data, fs, frameLen=100, isplot=True):
"""
计算声压曲线
2020-2-26 Jie Y. Init
:param data: 语音信号数据
:param fs: 采样率
:param frameLen: 计算声压的时间长度(ms单位)
:param isplot: 是否绘图,默认是
:return: 返回声压列表spls
"""
def spl_cal(s, fs, frameLen):
"""
根据数学公式计算单个声压值
$y=\sqrt(\sum_{i=1}^Nx^2(i))$
2020-2-26 Jie Y. Init
:param s: 输入数据
:param fs: 采样率
:param frameLen: 计算声压的时间长度(ms单位)
:return: 单个声压数值
"""
l = len(s)
M = frameLen * fs / 1000
if not l == M:
exit('输入信号长度与所定义帧长不等!')
# 计算有效声压
pp = 0
for i in range(int(M)):
pp += (s[i] * s[i])
pa = np.sqrt(pp / M)
p0 = 2e-5
spl = 20 * np.log10(pa / p0)
return spl
length = len(data)
M = fs * frameLen // 1000
m = length % M
if not m < M // 2:
# 最后一帧长度不小于M的一半
data = np.hstack((data, np.zeros(M - m)))
else:
# 最后一帧长度小于M的一半
data = data[:M * (length // M)]
spls = np.zeros(len(data) // M)
for i in range(length // M - 1):
s = data[i * M:(i + 1) * M]
spls[i] = spl_cal(s, fs, frameLen)
if isplot:
plt.subplot(211)
plt.plot(data)
plt.subplot(212)
plt.step([i for i in range(len(spls))], spls)
plt.show()
return spls
sb = soundBase('C2_3_y.wav')
data, fs = sb.audioread()
sb.SPL(data, fs)
声音的有效声压与基准声压之比,取以10为底的对数,再乘以20,即为声压级,通常以符号 L p L_p Lp表示,单位为dB。
L p = 20 lg P e p r e f ( d B ) L_p=20\lg\frac{P_e}{p_{ref}}(dB) Lp=20lgprefPe(dB)
其中, P e P_e Pe为待测声压的有效值, P r e f P_{ref} Pref为参考声压,在空气中一般取 2 × 1 0 − 5 P a 2\times 10^{-5}Pa 2×10−5Pa。
在物理学巾,声波在单位时间内作用在与其传递方向垂直的单位面积上的能量称为声强。日常生活中能听到的声音其强度范围很大,最大和最小之间可达 1 0 12 10^{12} 1012倍。
用声强的物理学单位表示声音强弱很不方便。当人耳听到两个强度不同的声音时,感觉的大小大致上与两个卢强比值的对数成比例。因此,用对数尺度来表示声音强度的等级,其单位为分贝(dB) 。
L I = 10 lg ( I / I 0 ) ( d B ) L_I=10\lg (I/I_0)(dB) LI=10lg(I/I0)(dB)
在声学中, I 0 = 1 × 1 0 − 12 W / m 2 I_0=1\times 10^{-12}W/m^2 I0=1×10−12W/m2。
对于球面波和平面波,声压与声强的关系是:
I = P 2 / ( ρ ⋅ c ) I=P^2/(\rho·c) I=P2/(ρ⋅c)
其中, ρ \rho ρ为空气密度, c c c为声速,在标准大气压和20摄氏度的环境下, ρ ⋅ c = 408 P a ⋅ s / m \rho·c=408 Pa·s/m ρ⋅c=408Pa⋅s/m,这个数值叫国际单位值,也叫瑞丽,称为空气对声波的特性阻抗。
响度描述的是声音的响亮程度,表示人耳对声音的主观感受,其计量单位是宋。定义为声压级为40dB的1 kHz纯音的响度为1 Son (宋) 。人耳对声音的感觉,不仅和声压有关,还和频率有关。声压级相同,频率不同的声音,听起来响亮程度也不同。如空压机与电锯,同是100dB声压级的噪声,昕起来电锯声要响得多。按人耳对声音的感觉特性,依据卢压和频率定出人对声音的主观音响感觉量,称为响度级,单位为方,符号phon。根据国际协议规定,OdB声级的1000 Hz纯音的晌度级定义为0 phon。其他频率声音的声级与响度级的对应关系,要从等响度曲线才能查出。
from soundBase import soundBase
from random import randint
import matplotlib.pyplot as plt
import numpy as np
# 2.3 练习1
sb = soundBase('C2_3_y.wav')
data, fs, nbits = sb.audioread()
# sb.SPL(data, fs)
spl, freq = sb.iso226(50)