python音频处理用到的操作的示例代码


Posted in Python onOctober 27, 2017

前言

本文主要记录python下音频常用的操作,以.wav格式文件为例。其实网上有很多现成的音频工具包,如果仅仅调用,工具包是更方便的。

更多pyton下的操作可以参考: 用python做科学计算

1、批量读取.wav文件名:

这里用到字符串路径:

1.通常意义字符串(str)
2.原始字符串,以大写R 或 小写r开始,r'',不对特殊字符进行转义
3.Unicode字符串,u'' basestring子类

如:

path = './file/n'

path = r'.\file\n'

path = '.\\file\\n'

三者等价,右划线\为转义字符,引号前加r表示原始字符串,而不转义(r:raw string).

常用获取帮助的方式:

>>> help(str)
>>> dir(str)
>>> help(str.replace)

2、读取.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]

其中最后一行为常用的音频参数:

  1. nchannels:声道数
  2. sampwidth:量化位数(byte)
  3. framerate:采样频率
  4. nframes:采样点数

单通道

对应code:

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:无。

结果图:

python音频处理用到的操作的示例代码

多通道

这里通道数为3,主要借助np.reshape一下,其他同单通道处理完全一致,对应code:

# -*- coding: utf-8 -*-

"""

Created on Wed May 3 12:15:34 2017

 

@author: Nobleding

"""

 

import wave

import matplotlib.pyplot as plt

import numpy as np

import os

 

filepath = "./data/" #添加路径

filename= os.listdir(filepath) #得到文件夹下的所有文件名称 

f = wave.open(filepath+filename[0],'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幅值归一化

waveData = np.reshape(waveData,[nframes,nchannels])

f.close()

# plot the wave

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

plt.figure()

plt.subplot(5,1,1)

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

plt.xlabel("Time(s)")

plt.ylabel("Amplitude")

plt.title("Ch-1 wavedata")

plt.grid('on')#标尺,on:有,off:无。

plt.subplot(5,1,3)

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

plt.xlabel("Time(s)")

plt.ylabel("Amplitude")

plt.title("Ch-2 wavedata")

plt.grid('on')#标尺,on:有,off:无。

plt.subplot(5,1,5)

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

plt.xlabel("Time(s)")

plt.ylabel("Amplitude")

plt.title("Ch-3 wavedata")

plt.grid('on')#标尺,on:有,off:无。

plt.show()

效果图:

python音频处理用到的操作的示例代码

单通道为多通道的特例,所以多通道的读取方式对任意通道wav文件都适用。需要注意的是,waveData在reshape之后,与之前的数据结构是不同的。即waveData[0]等价于reshape之前的waveData,但不影响绘图分析,只是在分析频谱时才有必要考虑这一点。

3、wav写入

涉及到的主要指令有三个:

参数设置:

nchannels = 1 #单通道为例

sampwidth = 2

fs = 8000

data_size = len(outData)

framerate = int(fs)

nframes = data_size

comptype = "NONE"

compname = "not compressed"

outwave.setparams((nchannels, sampwidth, framerate, nframes, comptype, compname))

待写入wav文件的存储路径及文件名:

outfile = filepath+'out1.wav'

outwave = wave.open(outfile, 'wb')#定义存储路径以及文件名

数据的写入:

for v in outData:
outwave.writeframes(struct.pack('h', int(v * 64000 / 2)))#outData:16位,-32767~32767,注意不要溢出

单通道数据写入:

import wave

#import matplotlib.pyplot as plt

import numpy as np

import os

import struct

 

#wav文件读取

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幅值归一化

f.close()

#wav文件写入

outData = waveData#待写入wav的数据,这里仍然取waveData数据

outfile = filepath+'out1.wav'

outwave = wave.open(outfile, 'wb')#定义存储路径以及文件名

nchannels = 1

sampwidth = 2

fs = 8000

data_size = len(outData)

framerate = int(fs)

nframes = data_size

comptype = "NONE"

compname = "not compressed"

outwave.setparams((nchannels, sampwidth, framerate, nframes,

  comptype, compname))

 

for v in outData:

    outwave.writeframes(struct.pack('h', int(v * 64000 / 2)))#outData:16位,-32767~32767,注意不要溢出

outwave.close()

多通道数据写入:

多通道的写入与多通道读取类似,多通道读取是将一维数据reshape为二维,多通道的写入是将二维的数据reshape为一维,其实就是一个逆向的过程:

import wave

#import matplotlib.pyplot as plt

import numpy as np

import os

import struct

 

#wav文件读取

filepath = "./data/" #添加路径

filename= os.listdir(filepath) #得到文件夹下的所有文件名称 

f = wave.open(filepath+filename[0],'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幅值归一化

waveData = np.reshape(waveData,[nframes,nchannels])

f.close()

#wav文件写入

outData = waveData#待写入wav的数据,这里仍然取waveData数据

outData = np.reshape(outData,[nframes*nchannels,1])

outfile = filepath+'out2.wav'

outwave = wave.open(outfile, 'wb')#定义存储路径以及文件名

nchannels = 3

sampwidth = 2

fs = 8000

data_size = len(outData)

framerate = int(fs)

nframes = data_size

comptype = "NONE"

compname = "not compressed"

outwave.setparams((nchannels, sampwidth, framerate, nframes,

  comptype, compname))

 

for v in outData:

    outwave.writeframes(struct.pack('h', int(v * 64000 / 2)))#outData:16位,-32767~32767,注意不要溢出

outwave.close()

这里用到struct.pack(.)二进制的转化:

python音频处理用到的操作的示例代码

例如:

python音频处理用到的操作的示例代码

python音频处理用到的操作的示例代码

4、音频播放

wav文件的播放需要用到pyaudio,安装包点击这里。我将它放在\Scripts文件夹下,cmd并切换到对应目录

pip install PyAudio-0.2.9-cp35-none-win_amd64.whl

pyaudio安装完成。

Pyaudio主要用法:

主要列出pyaudio对象的open()方法的参数:

  1. rate:采样率
  2. channels:声道数
  3. format:采样值的量化格式,值可以为paFloat32、paInt32、paInt24、paInt16、paInt8等。下面的例子中,使用get_from_width()将值为2的sampwidth转换为paInt16.
  4. input:输入流标志,Ture表示开始输入流
  5. output:输出流标志

给出对应code:

import wave

import pyaudio 

import os

 

#wav文件读取

filepath = "./data/" #添加路径

filename= os.listdir(filepath) #得到文件夹下的所有文件名称 

f = wave.open(filepath+filename[0],'rb')

params = f.getparams()

nchannels, sampwidth, framerate, nframes = params[:4]

#instantiate PyAudio 

p = pyaudio.PyAudio() 

#define stream chunk  

chunk = 1024 

#打开声音输出流

stream = p.open(format = p.get_format_from_width(sampwidth), 

        channels = nchannels, 

        rate = framerate, 

        output = True) 

 

#写声音输出流到声卡进行播放

data = f.readframes(chunk) 

i=1

while True: 

  data = f.readframes(chunk)

  if data == b'': break

  stream.write(data)  

f.close()

#stop stream 

stream.stop_stream() 

stream.close() 

#close PyAudio 

p.terminate()

因为是python3.5,判断语句if data == b'': break 的b不能缺少。

5、信号加窗

通常对信号截断、分帧需要加窗,因为截断都有频域能量泄露,而窗函数可以减少截断带来的影响。

窗函数在scipy.signal信号处理工具箱中,如hamming窗:

import scipy.signal as signal

pl.plot(signal.hanning(512))

利用上面的函数,绘制hanning窗:

import pylab as pl

import scipy.signal as signal

pl.figure(figsize=(6,2))

pl.plot(signal.hanning(512))

python音频处理用到的操作的示例代码

6、信号分帧

信号分帧的理论依据,其中x是语音信号,w是窗函数:

python音频处理用到的操作的示例代码

加窗截断类似采样,为了保证相邻帧不至于差别过大,通常帧与帧之间有帧移,其实就是插值平滑的作用。

给出示意图:

python音频处理用到的操作的示例代码

这里主要用到numpy工具包,涉及的指令有:

  1. np.repeat:主要是直接重复
  2. np.tile:主要是周期性重复

对比一下:

向量情况:python音频处理用到的操作的示例代码

矩阵情况:

对于数据:python音频处理用到的操作的示例代码

repeat操作:python音频处理用到的操作的示例代码

tile操作:python音频处理用到的操作的示例代码

对应结果:

python音频处理用到的操作的示例代码

python音频处理用到的操作的示例代码

对应分帧的代码实现:

这是没有加窗的示例:

import numpy as np

import wave

import os

#import math

 

def enframe(signal, nw, inc):

  '''将音频信号转化为帧。

  参数含义:

  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(winfunc(nw),(nf,1)) #window窗函数,这里默认取1

#  return frames*win  #返回帧信号矩阵

  return frames

def wavread(filename):

  f = wave.open(filename,'rb')

  params = f.getparams()

  nchannels, sampwidth, framerate, nframes = params[:4]

  strData = f.readframes(nframes)#读取音频,字符串格式

  waveData = np.fromstring(strData,dtype=np.int16)#将字符串转化为int

  f.close()

  waveData = waveData*1.0/(max(abs(waveData)))#wave幅值归一化

  waveData = np.reshape(waveData,[nframes,nchannels]).T

  return waveData

 

filepath = "./data/" #添加路径

dirname= os.listdir(filepath) #得到文件夹下的所有文件名称 

filename = filepath+dirname[0]

data = wavread(filename)

nw = 512

inc = 128

Frame = enframe(data[0], nw, inc)

如果需要加窗,只需要将函数修改为:

def enframe(signal, nw, inc, winfunc):

  '''将音频信号转化为帧。

  参数含义:

  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(winfunc,(nf,1)) #window窗函数,这里默认取1

  return frames*win  #返回帧信号矩阵

其中窗函数,以hamming窗为例:

winfunc = signal.hamming(nw)

Frame = enframe(data[0], nw, inc, winfunc)

调用即可。

7、语谱图

其实得到了分帧信号,频域变换取幅值,就可以得到语谱图,如果仅仅是观察,matplotlib.pyplot有specgram指令:

import wave

import matplotlib.pyplot as plt

import numpy as np

import os

 

filepath = "./data/" #添加路径

filename= os.listdir(filepath) #得到文件夹下的所有文件名称 

f = wave.open(filepath+filename[0],'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幅值归一化

waveData = np.reshape(waveData,[nframes,nchannels]).T

f.close()

# plot the wave

plt.specgram(waveData[0],Fs = framerate, scale_by_freq = True, sides = 'default')

plt.ylabel('Frequency(Hz)')

plt.xlabel('Time(s)')

plt.show()

python音频处理用到的操作的示例代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用python结合jieba和wordcloud实现词云效果
Sep 05 Python
Python获取当前公网ip并自动断开宽带连接实例代码
Jan 12 Python
python 显示数组全部元素的方法
Apr 19 Python
一条命令解决mac版本python IDLE不能输入中文问题
May 15 Python
Django 中使用流响应处理视频的方法
Jul 20 Python
如何在Django中添加没有微秒的 DateTimeField 属性详解
Jan 30 Python
Python流行ORM框架sqlalchemy安装与使用教程
Jun 04 Python
linux环境中没有网络怎么下载python
Jul 07 Python
Python selenium的基本使用方法分析
Dec 21 Python
python GUI库图形界面开发之PyQt5信号与槽基本操作
Feb 25 Python
tensorflow 2.0模式下训练的模型转成 tf1.x 版本的pb模型实例
Jun 22 Python
keras.utils.to_categorical和one hot格式解析
Jul 02 Python
彻底理解Python list切片原理
Oct 27 #Python
Python在不同目录下导入模块的实现方法
Oct 27 #Python
Django视图之ORM数据库查询操作API的实例
Oct 27 #Python
浅谈python函数之作用域(python3.5)
Oct 27 #Python
python+pyqt实现右下角弹出框
Oct 26 #Python
python中模块的__all__属性详解
Oct 26 #Python
Python内建函数之raw_input()与input()代码解析
Oct 26 #Python
You might like
PHP 程序员的调试技术小结
2009/11/15 PHP
php float不四舍五入截取浮点型字符串方法总结
2013/10/28 PHP
PHP批量上传图片的具体实现方法介绍.
2014/02/26 PHP
PHP中使用php://input处理相同name值的表单数据
2015/02/03 PHP
php 广告点击统计代码(php+mysql)
2018/02/21 PHP
关于jQuery新的事件绑定机制on()的使用技巧
2013/04/26 Javascript
A标签触发onclick事件而不跳转的多种解决方法
2013/06/27 Javascript
javascript的propertyIsEnumerable()方法使用介绍
2014/04/09 Javascript
javascript生成大小写字母
2015/07/03 Javascript
javascript滚轮控制模拟滚动条
2016/10/19 Javascript
jQuery实现的简单拖动层示例
2017/02/22 Javascript
jQuery实现按比例缩放图片的方法
2017/04/29 jQuery
微信小程序 图片上传实例详解
2017/05/05 Javascript
React router动态加载组件之适配器模式的应用详解
2018/09/12 Javascript
微信小程序实现留言板
2018/10/31 Javascript
Vue中错误图片的处理的实现代码
2019/11/07 Javascript
Vue实现购物车实例代码两则
2020/05/30 Javascript
python 类对象和实例对象动态添加方法(分享)
2017/12/31 Python
基于numpy.random.randn()与rand()的区别详解
2018/04/17 Python
python中字符串内置函数的用法总结
2018/09/13 Python
Python 正则表达式 re.match/re.search/re.sub的使用解析
2019/07/22 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
flask框架自定义url转换器操作详解
2020/01/25 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
实例讲解CSS3中的border-radius属性
2015/08/18 HTML / CSS
Sisley法国希思黎中国官网:享誉全球的奢华植物美容品牌
2019/06/30 全球购物
麦当劳印度网上订餐:McDelivery
2020/03/16 全球购物
英语专业推荐信
2013/11/16 职场文书
大学考试作弊检讨书
2014/01/30 职场文书
村级个人对照检查材料
2014/08/22 职场文书
解除劳动合同协议书
2014/09/17 职场文书
会议通知范文
2015/04/15 职场文书
信用卡收入证明范本
2015/06/12 职场文书
2016年感恩母亲节活动总结
2016/04/01 职场文书
AJAX引擎原理以及XmlHttpRequest对象的axios、fetch区别详解
2022/04/09 Javascript
解决Mysql中的innoDB幻读问题
2022/04/29 MySQL