周末没事,在家用pyaudio捣鼓了一下wav的读入,播放,与频谱分析.
正常人听觉的频率范围大约在20Hz~20kHz之间。为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质。
先上两个链接:
比特率:https://baike.baidu.com/item/%E6%AF%94%E7%89%B9%E7%8E%87/1022775?fr=aladdin
PCM编码:https://baike.baidu.com/item/pcm%E7%BC%96%E7%A0%81/10865033?fr=aladdin
摘一些出来学习:
1.一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,
比特率= 44.1K×16×2 =1411.2 Kbps。
我们常见的Audio CD就采用了PCM编码,一张光盘的容量只能容纳72分钟的音乐信息,而常见的wav歌曲大部分是PCM格式的。
2.数据了计算:我找了首刘惜君-我很快乐
数据量=(采样频率×采样位数bit×声道数×时间)/8=[44.1×1000×16×2×(3×60+33)] /(8×1024×1024) =37573200B约35.83MB
算出来的大小与歌曲也一样,大小:35.8 MB (37,643,974 字节);占用空间:35.9 MB (37,650,432 字节)
3.一帧PCM是:2048次采样组成的(网上搜到的),但是我自己用数据算了下,感觉不对,先写下面,有懂的帮指导一下:
采样率framerate:44100Hz
帧数nframes:9410940
时长time:213s
数据量:37573200Byte
帧数nframes/时长time=9410940/213=44182帧/秒,约等与采样率,怎么回事,我算错了么。。。汗
如果按2048次计算,一帧时间播放时间 = 2048 * 1000000/44100= 46.4ms,一帧的解码时间须控制在46.4ms内。
4.PCM格式
PCM(Pulse Code Modulation)也被称为 脉码编码调制。PCM中的声音数据没有被压缩,如果是单声道的文件,采样数据按时间的先后顺序依次存入。(它的基本组织单位是BYTE(8bit)或WORD(16bit))
样本大小 数据格式 最小值 最大值
8位PCM unsigned int 0 225
16位PCM int -32767 32767
4.文件格式
5.代码
#引入库
import wave
import numpy as np
from pyaudio import PyAudio
import pylab
import matplotlib.pyplot as plt
#定义数据流块
chunk = 2048
#只读方式打开wav文件
f = wave.open("that.wav","rb")
#创建PyAudio对象:
p = PyAudio()
#打开数据流
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
channels = f.getnchannels(),
rate = f.getframerate(),
output = True)
#读取数据
# _wave_params(nchannels=2, sampwidth=2, framerate=44100, nframes=9410940, comptype='NONE', compname='not compressed')
#(声道数,采样精度,采样率,帧数,......)
params = f.getparams()
print(params)
nchannels,sampwidth,framerate,nframes = params[0],params[1],params[2],params[3]
#读取完整的帧数据到datawav中,这是一个string类型的数据
datawav = f.readframes(nframes)
#将f关掉
f.close()
# with open("t.txt","w") as ftxt:
#
# ftxt.writelines(str(datawav[:10000]))
#
# ftxt.close()
#将波形数据转换为数组
# A new 1-D array initialized from raw binary or text data in a string.
datause = np.fromstring(datawav, dtype=np.short)
#将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。
datause.shape = -1, 2
#将数组转置,分别得到两个声道的序列
datause = datause.T
#time 得到每帧的绝对时间,也是一个数组,datause[0]datause[1]配对形成系列点坐标
#音频帧的播放时长 = 一个帧对应的采样点个数 / 采样频率(单位为s)
# 则,当前一帧的播放时间 = 2048* 1000000/44100= 46.4ms
time = np.arange(0, nframes) * (1.0/framerate) ##* chunk
#采样点数,修改采样点数和起始位置进行不同位置和长度的音频波形分析
#根据采样定理知采样频率要大于信号频率2倍,所以这里设置采样频率为44100赫兹
N = 44100 #每秒采样次数
start = 100 * N #开始采样位置
nsamp = 10 * N #采样区间时间长度
wavedata = datause[0][start:start+nsamp]
x=np.linspace(0,1,nsamp)
yy = np.fft.fft(wavedata)
yf = abs(yy) #取绝对值
yf1 = yf/nsamp #归一化处理
yf2 = yf1[range(int(nsamp//2))] #由于对称性,只取一半区间
fre = np.arange(len(yy))
fre2 = fre[range(int(len(x)//2))] #取一半区间
##Original wave
plt.subplot(221)
plt.plot(x[0:nsamp//50],wavedata[0:nsamp//50])
plt.title('Original wave')
##绘制频谱图
plt.subplot(222)
plt.plot(fre,yf,'r')
plt.title('FFT of Mixed wave(two sides frequency range)',fontsize=7,color='#7A378B')
#归一化
plt.subplot(223)
plt.plot(fre,yf1,'g')
plt.title('FFT of Mixed wave(normalization)',fontsize=9,color='r')
#一半
plt.subplot(224)
plt.plot(fre2,yf2,'b')
plt.title('FFT of Mixed wave',fontsize=10,color='#F08080')
plt.show()
stream.write(datawav[4*start:4*start+4*nsamp])##length datawav 37643760;length datause 18821880;length wavedata 441000
##注意,四个字节为一个采样点
# plt.title("Night.wav's Frames")
# plt.subplot(211)
# plt.plot(time, datause[0],color = 'green')
# plt.subplot(212)
# plt.plot(time, datause[1])
# plt.show()
#播放
# while True:
# data = f.readframes(chunk)
# stream.write(data)
# print(data)
# if data == b'':
# break
#停止数据流
stream.stop_stream()
stream.close()
#关闭 PyAudio
p.terminate()
6.频谱分析图
7.歌曲地址
https://pan.baidu.com/s/1hmeXmfUxQVYfBd0EGKGCYQ
参考:
https://www.cnblogs.com/lzxwalex/p/6922099.html
https://www.cnblogs.com/lidabo/p/3729615.html
https://www.cnblogs.com/lzxwalex/p/6922099.html
http://blog.sina.com.cn/s/blog_40793e970102w3m2.html
https://blog.csdn.net/pi9nc/article/details/12570841