当前位置:   article > 正文

Python语音处理入门_python 语音

python 语音

参考资料:

腾讯云 Python Wave模块开发者手册

Python Wave:声音的输入输出

NumPy Matplotlib | 菜鸟教程

subplot

python音频处理用到的操作

Python中的X[:,0]和X[:,1]

Python语音短时能量计算

 

实验目的:

1、 读取音频数据

2、 绘制单通道及双通道音频波形

3、 计算语音信号短时能量与短时过零率

4、 绘制语谱图并观察语谱图中音频的基音周期、频率与共振峰

 

准备工作:

       首先,我们需要 import 几个工具包,一个是 python 标准库中的 wave 模块,用于音频处理操作,另外两个是 numpy 和 matplot,提供数据处理函数,这两个工具包的安装请参考 Python图像处理入门中的相关介绍。

 

一:读取本地音频数据

       处理音频第一步是需要从让计算机“听到”声音,这里我们使用 python 标准库中自带的 wave模块进行音频参数的获取。

(1) 导入 wave 模块

(2) 使用 wave 中的函数 open 打开音频文件,wave.open(file,mode)函数带有两个参数, 第一个 file 是所需要打开的文件名及路径,使用字符串表示;第二个 mode 是打开的模式,也是用字符串表示 (’rb’或’wb’)

(3) 打开音频后使用 getparams()  获取音频基本的相关参数

getparams:

一次性返回所有的WAV文件的格式信息,它返回的是一个组元(tuple):声道数, 量化位数(byte单位), 采样频率, 采样点数, 压缩类型, 压缩类型的描述。wave模块只支持非压缩的数据,因此可以忽略最后两个信息。

nchannels:声道数;

sampwidth:量化位数或量化深度(byte);

framerate:采样频率;

nframes:采样点数

  1. # 导入 wave 模块
  2. import wave
  3. # 用于绘制波形图
  4. import matplotlib.pyplot as plt
  5. # 用于计算波形数据
  6. import numpy as np
  7. # 用于系统处理,如读取本地音频文件
  8. import os
  9. # 打开WAV文档
  10. f = wave.open(r"2.wav",'rb' )
  11. # 读取格式信息
  12. params = f.getparams ()
  13. nchannels,sampwidth, framerate, nframes = params [:4]
  14. print(framerate)

仅支持特定格式的wav,手机录音的wav不经过处理无法使用

网络下载的wav素材测试通过

 

二:读取单通道音频,并绘制波形图(常见音频为左右2个声道)

(1) 通过第一步,可以继续读取音频数据本身,保存为字符串格式

readframes:

读取声音数据,传递一个参数指定需要读取的长度(以取样点为单位),readframes返回的是二进制数据(一大堆bytes),在Python中用字符串表示二进制数据。

strData = f.readframes(nframes)

(2) 如果需要绘制波形图,则需要将字符串格式的音频数据转化为 int 类型

fromstring:

根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组。

通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式。

waveData = np.fromstring(strData,dtype=np.int16)

此处需要使用到 numpy 进行数据格式的转化

(3) 将幅值归一化

把数据变成(0,1)之间的小数。主要是为了数据处理方便提出来的,把数据映射到0~1范围之内处理,更加便捷快速。

waveData = waveData*1.0/(max(abs(waveData)))

这一步去掉也可画出波形图,大家可以尝试不用此步,找出波形图的不同

(4) 绘制图像

通过取样点数和取样频率计算出取样的时间:

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

plot:

1、plot(y)

以y的分量为纵坐标,以元素序号为横坐标,用直线依次连接数据点。

2、plot(x,y)

以x为横坐标,y为纵坐标。

3、plot(x1,y1,x2,y2,……)

在此格式中,每对x,y必须符合plot(x,y)中的要求,不同对之间没有影响,命令将对每一对x,y绘制曲线。

subplot:

subplot(m,n,p)

m 代表行,n 代表列,将数字窗口分成m×n的网格,p 代表的待绘图形的位置序号。

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. f = wave.open(r"di.wav",'rb' )
  10. params = f.getparams ()
  11. nchannels,sampwidth, framerate, nframes = params [:4]
  12. print(framerate)
  13. # 读取波形数据
  14. strData = f.readframes(nframes)
  15. # 将字符串转换为16位整数
  16. waveData = np.fromstring(strData,dtype=np.int16)
  17. # 幅值归一化
  18. waveData = waveData*1.0/(max(abs(waveData)))
  19. #计算音频的时间
  20. time = np.arange(0,nframes)*(1.0 / framerate)
  21. plt.plot(time,waveData)
  22. plt.xlabel("Time(s)")
  23. plt.ylabel("Amplitude")
  24. plt.title("Single channel wavedata")
  25. plt.show()

自己录的还是不行,下载的可以

如图

 

三: 多通道语音数据读取

(1) 唯一不一样的地方就是 waveData 是一个多维的矩阵了。

plt.plot(time,waveData[:,n])

#绘制waveData数据的第n列,即音频第n个通道的数据

reshape:

b = reshape(a,m,n)

更改矩阵的行列数,返回一个m*n的矩阵b, b中元素是按列从a中得到的。

如果a中元素个数没有m*n个, 则会报错。

waveData[:,0]

表示对waveData这个二维数组,取第一维中的所有数据,取第二维中第0(或1)个数据

waveData[:,0] 取所有行的第0个数据,

waveData[:,1] 取所有行的第1个数据。

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. f = wave.open(r"3.wav",'rb' )
  10. params = f.getparams ()
  11. nchannels,sampwidth, framerate, nframes = params [:4]#从0~ 4之前的数
  12. print(nchannels,sampwidth,framerate,nframes)
  13. # 读取波形数据
  14. strData = f.readframes(nframes)
  15. # 将波形数据转换为数组
  16. waveData = np.fromstring(strData,dtype=np.int16)
  17. waveData = waveData*1.0/(max(abs(waveData)))
  18. time = np.arange(0,nframes)*(1.0 / framerate)#计算音频的时间
  19. waveData = np.reshape(waveData,[nframes,nchannels])
  20. f.close()
  21. # 绘制波形
  22. plt.figure()
  23. plt.subplot(5,1,1)
  24. plt.plot(time,waveData[:,0])
  25. plt.xlabel("Time(s)")
  26. plt.ylabel("Amplitude")
  27. plt.title("Ch-1 wavedata")
  28. plt.subplot(5,1,3)
  29. plt.plot(time,waveData[:,1])
  30. plt.xlabel("Time(s)")
  31. plt.ylabel("Amplitude")
  32. plt.title("Ch-2 wavedata")
  33. plt.show()

这里用的双通道wav

四:语音信号短时能量

 计算较短时间内的语音能量。这里短时指的是一帧(256个采样点)。

len:返回列表元素的个数。

数据结构--列表

energy = [] 新建空列表

energy.append(sum) 列表末尾增加元素

aList.sort() 列表内元素排序

def calEnergy(wave_data) :
    energy = []
    sum = 0
    frameSize = 256
    for i in range(len(wave_data)) :#计算每一帧的数据和
        sum = sum + (wave_data[i] * wave_data[i])#采样点数据平方
        if (i + 1) % frameSize  == 0 :
            energy.append(sum)
            sum = 0
        elif i == len(wave_data) - 1 :
            energy.append(sum)
    return energy

energy = calEnergy(waveData[:,0])

time2 = np.arange(0, len(energy)) * (len(waveData[:,0])/len(energy) / framerate)

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. def calEnergy(wave_data) :
  10. energy = []
  11. sum = 0
  12. frameSize = 256
  13. for i in range(len(wave_data)) :#计算每一帧的数据和
  14. sum = sum + (wave_data[i] * wave_data[i])#采样点数据平方
  15. if (i + 1) % frameSize == 0 :
  16. energy.append(sum)
  17. sum = 0
  18. elif i == len(wave_data) - 1 :
  19. energy.append(sum)
  20. return energy
  21. f = wave.open(r"3.wav",'rb' )
  22. params = f.getparams ()
  23. nchannels,sampwidth, framerate, nframes = params [:4]#从0~ 4之前的数
  24. print(nchannels,sampwidth,framerate,nframes)
  25. strData = f.readframes(nframes)
  26. waveData = np.fromstring(strData,dtype=np.int16)
  27. waveData = waveData*1.0/(max(abs(waveData)))
  28. time = np.arange(0,nframes)*(1.0 / framerate)#计算音频的时间
  29. waveData = np.reshape(waveData,[nframes,nchannels])
  30. f.close()
  31. plt.figure()
  32. plt.subplot(5,1,1)
  33. plt.plot(time,waveData[:,0])
  34. plt.xlabel("Time(s)")
  35. plt.ylabel("Amplitude")
  36. plt.title("Ch-1 wavedata")
  37. plt.subplot(5,1,3)
  38. plt.plot(time,waveData[:,1])
  39. plt.xlabel("Time(s)")
  40. plt.ylabel("Amplitude")
  41. plt.title("Ch-2 wavedata")
  42. plt.show()
  43. energy = calEnergy(waveData[:,0])
  44. time2 = np.arange(0, len(energy)) * (len(waveData[:,0])/len(energy) / framerate)
  45. plt.plot(time2, energy)
  46. plt.ylabel("short energy")
  47. plt.xlabel("time (seconds)")
  48. plt.show()

 

五:语音信号短时过零率

       在每帧中(256个采样点),语音信号通过零点(从正变为负或从负变为正)的次数。

overLap 部分重叠

切片
[ 0 ]    读取第一个值
[ -1 ]   取最后一个元素
[1: ]    去掉列表中第一个元素(下标为0),去后面的元素进行操作
[ :-1]   除了最后一个取全部
[ :-2]   从位置0到位置-2之前的数
[ ::-1]  取从后向前(相反)的元素
[2::-1] 取从下标为2的元素翻转读取
b = a[ i : j ]  表示复制 a[ i ] 到 a[ j -1],以生成新的list对象。

def ZeroCR(wave_data,frameSize,overLap):
    wlen = len(wave_data)
    step = frameSize - overLap
    frameNum = math.ceil(wlen/step)#帧的数量
    zcr = np.zeros((frameNum,1))
    for i in range(frameNum):#每帧过零的次数计算
        curFrame = wave_data[np.arange(i*step,min(i*step+frameSize,wlen))]
        curFrame = curFrame - np.mean(curFrame)
        zcr[i] = sum(curFrame[0:-1]*curFrame[1::]<=0)
    return zcr

frameSize = 256
overLap = 0
zcr = ZeroCR(waveData[:,0],frameSize,overLap)
time3 = np.arange(0, len(zcr)) * (len(waveData[:,0])/len(zcr) / framerate)

plt.plot(time3, zcr)
plt.ylabel("ZCR")
plt.xlabel("time (seconds)")
plt.show()

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. import math
  10. def calEnergy(wave_data) :
  11. energy = []
  12. sum = 0
  13. frameSize = 256
  14. for i in range(len(wave_data)) :#计算每一帧的数据和
  15. sum = sum + (wave_data[i] * wave_data[i])#采样点数据平方
  16. if (i + 1) % frameSize == 0 :
  17. energy.append(sum)
  18. sum = 0
  19. elif i == len(wave_data) - 1 :
  20. energy.append(sum)
  21. return energy
  22. def ZeroCR(wave_data,frameSize,overLap):
  23. wlen = len(wave_data)
  24. step = frameSize - overLap
  25. frameNum = math.ceil(wlen/step)#帧的数量
  26. zcr = np.zeros((frameNum,1))
  27. for i in range(frameNum):#每帧过零的次数计算
  28. curFrame = wave_data[np.arange(i*step,min(i*step+frameSize,wlen))]
  29. curFrame = curFrame - np.mean(curFrame)
  30. zcr[i] = sum(curFrame[0:-1]*curFrame[1::]<=0)
  31. return zcr
  32. f = wave.open(r"3.wav",'rb' )
  33. params = f.getparams ()
  34. nchannels,sampwidth, framerate, nframes = params [:4]#从0~ 4之前的数
  35. print(nchannels,sampwidth,framerate,nframes)
  36. strData = f.readframes(nframes)
  37. waveData = np.fromstring(strData,dtype=np.int16)
  38. waveData = waveData*1.0/(max(abs(waveData)))
  39. time = np.arange(0,nframes)*(1.0 / framerate)#计算音频的时间
  40. waveData = np.reshape(waveData,[nframes,nchannels])
  41. f.close()
  42. plt.figure()
  43. plt.subplot(5,1,1)
  44. plt.plot(time,waveData[:,0])
  45. plt.xlabel("Time(s)")
  46. plt.ylabel("Amplitude")
  47. plt.title("Ch-1 wavedata")
  48. plt.subplot(5,1,3)
  49. plt.plot(time,waveData[:,1])
  50. plt.xlabel("Time(s)")
  51. plt.ylabel("Amplitude")
  52. plt.title("Ch-2 wavedata")
  53. plt.show()
  54. energy = calEnergy(waveData[:,0])
  55. time2 = np.arange(0, len(energy)) * (len(waveData[:,0])/len(energy) / framerate)
  56. plt.plot(time2, energy)
  57. plt.ylabel("short energy")
  58. plt.xlabel("time (seconds)")
  59. plt.show()
  60. frameSize = 256
  61. overLap = 0
  62. zcr = ZeroCR(waveData[:,0],frameSize,overLap)
  63. time3 = np.arange(0, len(zcr)) * (len(waveData[:,0])/len(zcr) / framerate)
  64. plt.plot(time3, zcr)
  65. plt.ylabel("ZCR")
  66. plt.xlabel("time (seconds)")
  67. plt.show()

 

六:绘制语谱图

1.  绘制宽带语谱图

(1)设置帧长,包含采样点数,必须为2^n,n取小(如32,画出的图为宽带频谱图),n取大(如2048,画出的图为窄带频谱图)

framesize = 32

(2)计算离散傅里叶变换的点数,NFFT必须与时域的点数framsize相等,即不补零的FFT

NFFT = framesize

(3)设置帧与帧重叠部分采样点数,overlapSize约为每帧点数的1/3~1/2

overlapSize = 1.0 / 3 * framesize  

overlapSize = int(round(overlapSize))  # 取整

(4)绘制频谱图

plt.specgram(waveData[:,0],NFFT=NFFT,Fs=framerate,window=np.hanning(M=framesize), noverlap=overlapSize)

(5)绘制

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. import math
  10. def calEnergy(wave_data) :
  11. energy = []
  12. sum = 0
  13. frameSize = 256
  14. for i in range(len(wave_data)) :#计算每一帧的数据和
  15. sum = sum + (wave_data[i] * wave_data[i])#采样点数据平方
  16. if (i + 1) % frameSize == 0 :
  17. energy.append(sum)
  18. sum = 0
  19. elif i == len(wave_data) - 1 :
  20. energy.append(sum)
  21. return energy
  22. def ZeroCR(wave_data,frameSize,overLap):
  23. wlen = len(wave_data)
  24. step = frameSize - overLap
  25. frameNum = math.ceil(wlen/step)#帧的数量
  26. zcr = np.zeros((frameNum,1))
  27. for i in range(frameNum):#每帧过零的次数计算
  28. curFrame = wave_data[np.arange(i*step,min(i*step+frameSize,wlen))]
  29. curFrame = curFrame - np.mean(curFrame)
  30. zcr[i] = sum(curFrame[0:-1]*curFrame[1::]<=0)
  31. return zcr
  32. f = wave.open(r"3.wav",'rb' )
  33. params = f.getparams ()
  34. nchannels,sampwidth, framerate, nframes = params [:4]#从0~ 4之前的数
  35. print(nchannels,sampwidth,framerate,nframes)
  36. strData = f.readframes(nframes)
  37. waveData = np.fromstring(strData,dtype=np.int16)
  38. waveData = waveData*1.0/(max(abs(waveData)))
  39. time = np.arange(0,nframes)*(1.0 / framerate)#计算音频的时间
  40. waveData = np.reshape(waveData,[nframes,nchannels])
  41. f.close()
  42. plt.figure()
  43. plt.subplot(5,1,1)
  44. plt.plot(time,waveData[:,0])
  45. plt.xlabel("Time(s)")
  46. plt.ylabel("Amplitude")
  47. plt.title("Ch-1 wavedata")
  48. plt.subplot(5,1,3)
  49. plt.plot(time,waveData[:,1])
  50. plt.xlabel("Time(s)")
  51. plt.ylabel("Amplitude")
  52. plt.title("Ch-2 wavedata")
  53. plt.show()
  54. energy = calEnergy(waveData[:,0])
  55. time2 = np.arange(0, len(energy)) * (len(waveData[:,0])/len(energy) / framerate)
  56. plt.plot(time2, energy)
  57. plt.ylabel("short energy")
  58. plt.xlabel("time (seconds)")
  59. plt.show()
  60. frameSize = 256
  61. overLap = 0
  62. zcr = ZeroCR(waveData[:,0],frameSize,overLap)
  63. time3 = np.arange(0, len(zcr)) * (len(waveData[:,0])/len(zcr) / framerate)
  64. plt.plot(time3, zcr)
  65. plt.ylabel("ZCR")
  66. plt.xlabel("time (seconds)")
  67. plt.show()
  68. framesize = 32
  69. NFFT = framesize
  70. overlapSize = 1.0 / 3 * framesize
  71. overlapSize = int(round(overlapSize)) # 取整
  72. plt.specgram(waveData[:,0], NFFT=NFFT, Fs=framerate,
  73. window=np.hanning(M=framesize), noverlap=overlapSize)
  74. plt.ylabel('Frequency')
  75. plt.xlabel('Time')
  76. plt.ylim(0, 6000)
  77. plt.title("Wide Band Spectrum")
  78. plt.show()

 

2.绘制窄带语谱图

  1. import wave
  2. # 导入 wave 模块
  3. import matplotlib.pyplot as plt
  4. # 用于绘制波形图
  5. import numpy as np
  6. # 用于计算波形数据
  7. import os
  8. # 用于系统处理,如读取本地音频文件
  9. import math
  10. def calEnergy(wave_data) :
  11. energy = []
  12. sum = 0
  13. frameSize = 256
  14. for i in range(len(wave_data)) :#计算每一帧的数据和
  15. sum = sum + (wave_data[i] * wave_data[i])#采样点数据平方
  16. if (i + 1) % frameSize == 0 :
  17. energy.append(sum)
  18. sum = 0
  19. elif i == len(wave_data) - 1 :
  20. energy.append(sum)
  21. return energy
  22. def ZeroCR(wave_data,frameSize,overLap):
  23. wlen = len(wave_data)
  24. step = frameSize - overLap
  25. frameNum = math.ceil(wlen/step)#帧的数量
  26. zcr = np.zeros((frameNum,1))
  27. for i in range(frameNum):#每帧过零的次数计算
  28. curFrame = wave_data[np.arange(i*step,min(i*step+frameSize,wlen))]
  29. curFrame = curFrame - np.mean(curFrame)
  30. zcr[i] = sum(curFrame[0:-1]*curFrame[1::]<=0)
  31. return zcr
  32. f = wave.open(r"3.wav",'rb' )
  33. params = f.getparams ()
  34. nchannels,sampwidth, framerate, nframes = params [:4]#从0~ 4之前的数
  35. print(nchannels,sampwidth,framerate,nframes)
  36. strData = f.readframes(nframes)
  37. waveData = np.fromstring(strData,dtype=np.int16)
  38. waveData = waveData*1.0/(max(abs(waveData)))
  39. time = np.arange(0,nframes)*(1.0 / framerate)#计算音频的时间
  40. waveData = np.reshape(waveData,[nframes,nchannels])
  41. f.close()
  42. plt.figure()
  43. plt.subplot(5,1,1)
  44. plt.plot(time,waveData[:,0])
  45. plt.xlabel("Time(s)")
  46. plt.ylabel("Amplitude")
  47. plt.title("Ch-1 wavedata")
  48. plt.subplot(5,1,3)
  49. plt.plot(time,waveData[:,1])
  50. plt.xlabel("Time(s)")
  51. plt.ylabel("Amplitude")
  52. plt.title("Ch-2 wavedata")
  53. plt.show()
  54. energy = calEnergy(waveData[:,0])
  55. time2 = np.arange(0, len(energy)) * (len(waveData[:,0])/len(energy) / framerate)
  56. plt.plot(time2, energy)
  57. plt.ylabel("short energy")
  58. plt.xlabel("time (seconds)")
  59. plt.show()
  60. frameSize = 256
  61. overLap = 0
  62. zcr = ZeroCR(waveData[:,0],frameSize,overLap)
  63. time3 = np.arange(0, len(zcr)) * (len(waveData[:,0])/len(zcr) / framerate)
  64. plt.plot(time3, zcr)
  65. plt.ylabel("ZCR")
  66. plt.xlabel("time (seconds)")
  67. plt.show()
  68. framesize = 32
  69. NFFT = framesize
  70. overlapSize = 1.0 / 3 * framesize
  71. overlapSize = int(round(overlapSize)) # 取整
  72. plt.specgram(waveData[:,0], NFFT=NFFT, Fs=framerate,
  73. window=np.hanning(M=framesize), noverlap=overlapSize)
  74. plt.ylabel('Frequency')
  75. plt.xlabel('Time')
  76. plt.ylim(0, 6000)
  77. plt.title("Wide Band Spectrum")
  78. plt.show()
  79. framesize = 2048
  80. framelength = framesize / framerate
  81. NFFT = framesize
  82. overlapSize = 1.0 / 3 * framesize
  83. overlapSize = int(round(overlapSize))
  84. plt.specgram(waveData[:,0], NFFT=NFFT,Fs=framerate,
  85. window=np.hanning(M=framesize),noverlap=overlapSize)
  86. plt.ylabel('Frequency')
  87. plt.xlabel('Time')
  88. plt.ylim(0, 6000)
  89. plt.title("Narrow Band Spectrum")
  90. plt.show()

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号