python对语音信号处理(常用操作)

一、语音信号读取
1、语音信号三个重要的参数:声道数、取样频率和量化位数。

  • 声道数:单声道、双声道
  • 取样频率:一秒钟对声音采样的次数
  • 量化位数:用多少bit表达一次采样所采集的数据,通常有8bit、16bit、24bit和32bit等几种
    例:CD中所储存的声音信号是双声道、44.1kHz、16bit

2、 读取.wav文件
scipy方法:

from scipy.io import wavfile
import numpy as np

sample_rate, sig = wavfile.read('new.wav')
#sample_rate 采样率

pysoundfile方法:

import soundfile as sf

sig, sample_rate = sf.read('new.wav')

wave.open 用法:

wave.open(file,mode)
#mode可以是:
‘rb’,读取文件;
‘wb’,写入文件;
不支持同时读/写操作。

Wave_read.getparams用法:

f = wave.open(file,'rb')
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]  
#nchannels:声道数 sampwidth:量化位数(byte) framerate:采样频率 nframes:采样点数
  • 单通道
import wave
import matplotlib.pyplot as plt
import numpy as np
import os
 
filepath = "./data/" #添加路径
filename= os.listdir(filepath) #得到文件夹下的所有文件名称 
f = wave.open(filepath+filename[1],'rb')
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
strData = f.readframes(nframes)#读取音频,字符串格式
waveData = np.fromstring(strData,dtype=np.int16)#将字符串转化为int
waveData = waveData*1.0/(max(abs(waveData)))#wave幅值归一化
# plot the wave
time = np.arange(0,nframes)*(1.0 / framerate)
plt.plot(time,waveData)
plt.xlabel("Time(s)")
plt.ylabel("Amplitude")
plt.title("Single channel wavedata")
plt.grid('on')#标尺,on:有,off:无。
  • 双通道
# -*- coding: utf-8 -*-
import wave				            
import matplotlib.pyplot as plt		
import numpy as np 	            	

f = wave.open(r"./.wav", "rb")   #wave模块读取语音文件
params = f.getparams()			#一次性返回所有的音频参数,返回的是一个元组(声道数,量化位数(byte单位),采样频率,采样点数,压缩类型,压缩类型的描述)
nchannels, sampwidth, framerate, nframes = params[:4] #赋值声道数,量化位数,采样频率,采样点数
print(nchannels)# 输出声道数
print(sampwidth)# 输出量化位数
print(framerate)# 输出采样频率
print(nframes)  # 输出采样点数

str_data = f.readframes(nframes)   #指定需要读取的长度(以取样点为单位),返回的是字符串类型的数据
f.close()
wave_data = np.frombuffer(str_data, dtype=np.int16)  #将读取的字符串数据转换为一维short类型的数组。通过np.fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式
wave_data = wave_data*1.0/(max(abs(wave_data)))      #将数组归一化
wave_data = np.reshape(wave_data,[nframes,nchannels])

time = np.arange(0, nframes) * (1.0 / framerate)

#通过采样点数和取样频率计算出每个取样的时间
#画出语音的波形
plt.figure(figsize=(10,9))  #设置窗口属性
plt.subplot(211)
plt.plot(time, wave_data[:,0],c="g")
plt.xlabel("time (seconds)")
plt.ylabel("Amplitude")
plt.title("CH-1 wave_data")
plt.grid()
plt.subplot(212)
plt.plot(time, wave_data[:,1],c="g")
plt.xlabel("time (seconds)")
plt.ylabel("Amplitude")
plt.title("CH-2 wave_data")
plt.grid()
plt.show()

二、语音信号处理
1、预加重
语音信号的预加重,目的是为了对语音的高频部分进行加重,去除口唇辐射的影响,增加语音的高频分辨率。一般通过传递函数为
在这里插入图片描述
一阶FIR高通数字滤波器来实现预加重,其中a为预加重系数,0.9

pre_emphasis = 0.98
emphasized_signal = np.append(audio[0], audio[1:] - pre_emphasis * audio[:-1])
plt.plot(np.arange(emphasized_signal.shape[0]),emphasized_signal)
plt.show()

2、分帧
分帧是将不定长的音频切分成固定长度的小段。为了避免窗边界对信号的遗漏,因此对帧做偏移时候,帧间要有帧移(帧与帧之间需要重叠一部分),帧长(wlen) = 重叠(overlap)+帧移(inc)。inc为帧移,表示后一帧第前一帧的偏移量,fs表示采样率,fn表示一段语音信号的分帧数,N为语音数据长度
wlen为帧长,重叠部分为overlap,overlap=wlen - inc

fn=(N−overlap)/inc=(N−wlen)/inc+1

通常的选择是帧长25ms,帧移为10ms。接下来的操作是对单帧进行的。要分帧是因为语音信号是快速变化的,而傅里叶变换适用于分析平稳的信号。帧和帧之间的时间差常常取为10ms,这样帧与帧之间会有重叠,否则,由于帧与帧连接处的信号会因为加窗而被弱化,这部分的信息就丢失了。

#分帧函数
def enframe(signal, nw, inc, windown):
    '''将音频信号转化为帧。
    signal:原始音频型号
    nw:每一帧的长度(这里指采样点的长度,即采样频率乘以时间间隔)
    inc:相邻帧的间隔
    '''
    signal_length=len(signal) #信号总长度
    if signal_length<=nw: #若信号长度小于一个帧的长度,则帧数定义为1
        nf=1
    else: #否则,计算帧的总长度
        nf=int(np.ceil((1.0*signal_length-nw+inc)/inc))
        
    pad_length=int((nf-1)*inc+nw) #所有帧加起来总的铺平后的长度
    zeros=np.zeros((pad_length-signal_length,)) #不够的长度使用0填补,类似于FFT中的扩充数组操作
    pad_signal=np.concatenate((signal,zeros)) #填补后的信号记为pad_signal
    indices=np.tile(np.arange(0,nw),(nf,1))+np.tile(np.arange(0,nf*inc,inc),(nw,1)).T  #相当于对所有帧的时间点进行抽取,得到nf*nw长度的矩阵
    indices=np.array(indices,dtype=np.int32) #将indices转化为矩阵
    frames=pad_signal[indices] #得到帧信号
    win=np.tile(windown,(nf,1))  #window窗函数,这里默认取1
    return frames*win   #返回帧信号矩阵

3、加窗
通常对信号截断、分帧需要加窗,因为截断都有频域能量泄露,而窗函数可以减少截断带来的影响。窗函数在scipy.signal信号处理工具箱中,如hanning窗:

import matplotlib.pyplot as plt
import scipy.signal as signal
plt.figure(figsize=(6,2))
plt.plot(signal.hanning(512))

你可能感兴趣的:(python对语音信号处理(常用操作))