Skip to content

Commit 09d8c0a

Browse files
authored
Init 2-4
1 parent bfdcbd8 commit 09d8c0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+5088
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
2+
## 语言录制
3+
~~~py
4+
import pyaudio
5+
import wave
6+
7+
CHUNK = 1024
8+
FORMAT = pyaudio.paInt16
9+
CHANNELS = 2
10+
RATE = 16000
11+
RECORD_SECONDS = 2
12+
WAVE_OUTPUT_FILENAME = "Oldboy.wav"
13+
14+
p = pyaudio.PyAudio()
15+
16+
stream = p.open(format=FORMAT,
17+
channels=CHANNELS,
18+
rate=RATE,
19+
input=True,
20+
frames_per_buffer=CHUNK)
21+
22+
print("start recording......")
23+
24+
frames = []
25+
26+
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
27+
data = stream.read(CHUNK)
28+
frames.append(data)
29+
30+
print("end!")
31+
32+
stream.stop_stream()
33+
stream.close()
34+
p.terminate()
35+
36+
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
37+
wf.setnchannels(CHANNELS)
38+
wf.setsampwidth(p.get_sample_size(FORMAT))
39+
wf.setframerate(RATE)
40+
wf.writeframes(b''.join(frames))
41+
wf.close()
42+
~~~
43+
## 语音播放
44+
~~~py
45+
"""PyAudio Example: Play a WAVE file."""
46+
47+
import pyaudio
48+
import wave
49+
50+
CHUNK = 1024
51+
FILENAME = 'C2_1_y.wav'
52+
53+
54+
def player(filename=FILENAME):
55+
wf = wave.open(filename, 'rb')
56+
57+
p = pyaudio.PyAudio()
58+
59+
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
60+
channels=wf.getnchannels(),
61+
rate=wf.getframerate(),
62+
output=True)
63+
64+
data = wf.readframes(CHUNK)
65+
66+
while data != b'':
67+
stream.write(data)
68+
data = wf.readframes(CHUNK)
69+
70+
stream.stop_stream()
71+
stream.close()
72+
73+
p.terminate()
74+
75+
76+
player(FILENAME)
77+
~~~
78+
79+
## 读取并可视化
80+
~~~py
81+
import librosa # 填充,默认频率为22050,可以改变频率
82+
from scipy.io import wavfile # 原音无损
83+
import numpy as np
84+
import librosa.display
85+
import matplotlib.pyplot as plt
86+
fs, data = wavfile.read('C2_1_y.wav') # 原始频率,原始数据
87+
print("长度 = {0}".format(len(data) / fs))
88+
data1, sample_rate = librosa.load('C2_1_y.wav')
89+
print("长度 = {0}".format(len(data1) / sample_rate))
90+
plt.figure(figsize=(14, 5))
91+
librosa.display.waveplot(data1, sample_rate)
92+
plt.show()
93+
~~~
94+
## 通用基础类
95+
~~~py
96+
import pyaudio
97+
import wave
98+
import librosa
99+
import librosa.display
100+
import matplotlib.pyplot as plt
101+
102+
103+
# from scipy.io import wavfile
104+
105+
class soundBase:
106+
def __init__(self, path):
107+
self.path = path
108+
109+
def audiorecorder(self, len=2, formater=pyaudio.paInt16, rate=16000, frames_per_buffer=1024, channels=2):
110+
p = pyaudio.PyAudio()
111+
stream = p.open(format=formater, channels=channels, rate=rate, input=True, frames_per_buffer=frames_per_buffer)
112+
print("start recording......")
113+
frames = []
114+
for i in range(0, int(rate / frames_per_buffer * len)):
115+
data = stream.read(frames_per_buffer)
116+
frames.append(data)
117+
print("stop recording......")
118+
stream.stop_stream()
119+
stream.close()
120+
p.terminate()
121+
wf = wave.open(self.path, 'wb')
122+
wf.setnchannels(channels)
123+
wf.setsampwidth(p.get_sample_size(formater))
124+
wf.setframerate(rate)
125+
wf.writeframes(b''.join(frames))
126+
wf.close()
127+
128+
def audioplayer(self, frames_per_buffer=1024):
129+
wf = wave.open(self.path, 'rb')
130+
p = pyaudio.PyAudio()
131+
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
132+
channels=wf.getnchannels(),
133+
rate=wf.getframerate(),
134+
output=True)
135+
data = wf.readframes(frames_per_buffer)
136+
while data != b'':
137+
stream.write(data)
138+
data = wf.readframes(frames_per_buffer)
139+
140+
stream.stop_stream()
141+
stream.close()
142+
p.terminate()
143+
144+
def audiowrite(self):
145+
pass
146+
147+
def audioread(self):
148+
data, sample_rate = librosa.load(self.path)
149+
return data, sample_rate
150+
151+
def soundplot(self, data=[], sr=22050, size=(14, 5)):
152+
if len(data) == 0:
153+
data, _ = self.audioread()
154+
plt.figure(figsize=size)
155+
librosa.display.waveplot(data, sr=sr)
156+
plt.show()
157+
158+
159+
sb = soundBase('C2_1_y.wav')
160+
data, sr = sb.audioread()
161+
sb.soundplot(data, sr)
162+
163+
~~~
164+
## matlab版本更新后函数更新
165+
matlab老版本(如matlab2010)使用的函数名在新版本中已经取消了,对应关系如下:
166+
|||
167+
|--|--|
168+
|wavrecord|audiorecorder|
169+
|wavplay|audioplayer|
170+
|wavwrite|audioplayer|
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
## 信号相加
2+
读取了语音信号之后可以看到是一个一维数组,可以直接通过一维数组(列表)的形式进行操作。在两个序列长度不一样时候,可以在短的一个序列后补零。
3+
~~~py
4+
class soundBase:
5+
def __init__(self, path):
6+
self.path = path
7+
8+
def sound_add(self, data1, data2):
9+
if len(data1) < len(data2):
10+
tmp = np.zeros([len(data2)])
11+
for i in range(len(data1)):
12+
tmp[i] += data1[i]
13+
return tmp + data2
14+
elif len(data1) > len(data2):
15+
tmp = np.zeros([len(data1)])
16+
for i in range(len(data2)):
17+
tmp[i] += data2[i]
18+
return tmp + data1
19+
else:
20+
return data1 + data2
21+
~~~
22+
23+
## 卷积
24+
卷积是一个常用的计算,两个序列$x_1,x_2$的卷积表达式为:
25+
$$y(n)=\sum\limits_{k=-\infty}^{\infty}x_1(k)x_2(n-k)$$
26+
27+
对于离散信号来说:
28+
$$y(n)=\sum\limits_{k=0}^{N}x_1(k)x_2(n-k)$$
29+
30+
计算方式可以参考[一维信号的卷积认识](https://blog.csdn.net/sinat_18131557/article/details/103432004)
31+
32+
## 采样频率的转化
33+
采样频率的转化是为了做升采样和降采样。降采样是对序列$x(n)$间隔$D-1$个点进行抽取:
34+
$$x_D(m)=x(Dm)\tag{抽取}$$
35+
36+
其中$D$为正整数。为了米面抽取序列后频谱混叠,通常在抽取前将信号通过一个抗混叠滤波器。
37+
内插就是在原序列的样本点之间插入$I-1$个值,原始序列为$x(n)$,内插后的序列为$x_I(m)$
38+
$$x_I(m)=\left\{\begin{array}{ll}
39+
x(\frac{m}{I})&,m=0,±I,±2I...\\
40+
0&,others
41+
\end{array}\right.\tag{内插}$$
42+
43+
内插之后,通过低通滤波器,移植混叠信号。
44+
45+
在matlab中都可以通过`resample`函数来进行,通过配置参数的不同即可。在python的实现中,利用`audiowrite`的参数`fs`来实现,在读取信号的时候,输出fs,然后对fs进行变化后写入。
46+
~~~py
47+
class soundBase:
48+
def __init__(self, path):
49+
self.path = path
50+
51+
def audiowrite(self, data, fs, binary=True, channel=1, path=[]):
52+
if binary:
53+
wf = wave.open(self.path, 'wb')
54+
wf.setframerate(fs)
55+
wf.setnchannels(channel)
56+
wf.setsampwidth(2)
57+
wf.writeframes(b''.join(data))
58+
else:
59+
if len(path) == 0:
60+
path = self.path
61+
wavfile.write(path, fs, data)
62+
63+
def audioread(self):
64+
fs, data = wavfile.read(self.path)
65+
return data, fs
66+
67+
sb = soundBase('C2_2_y.wav')
68+
data, fs = sb.audioread()
69+
sb_cc = soundBase('C2_2_y_conved_2.wav')
70+
sb_c.audiowrite(data, fs * 2)
71+
~~~
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
## 声压
2+
声压是定量描述声波的最基本的物理量,它是由于声扰动产生的逾量压强,是空间位置和时间的函数。由于声压的测量比较易于实现,而且通过声压的测量也可以间接求得质点振速等其他声学参量,因此,声压已成为人们最为普遍采用的定量描述声披性质的物理量。
3+
### 有效声压
4+
通常讲的卢压指的是有效声压,即在一定时间间隔内将瞬时声压对时间求方均根值所得。设语音长度度为$T$, 离散点数为$N$, 则有效声压的计算公式为
5+
$$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}$$
6+
7+
8+
9+
其中$x$表示采样点。只要保证所取的点数$N$足够大,即可保证计算的准确性。用于计算声压级值的语音帧长一般为20ms、50ms、100ms、200ms以及500ms。计算的结果是一个序列。
10+
11+
~~~py
12+
class soundBase:
13+
def __init__(self, path):
14+
self.path = path
15+
16+
def audioread(self, formater='sample'):
17+
"""
18+
读取语音文件
19+
2020-2-26 Jie Y. Init
20+
:param formater: 获取数据的格式,为sample时,数据为float32的,[-1,1],同matlab同名函数. 否则为文件本身的数据格式
21+
:return: 语音数据data, 采样率fs
22+
"""
23+
fs, data = wavfile.read(self.path)
24+
if formater == 'sample':
25+
data, _ = librosa.load(self.path, sr=fs)
26+
return data, fs
27+
28+
def SPL(self, data, fs, frameLen=100, isplot=True):
29+
"""
30+
计算声压曲线
31+
2020-2-26 Jie Y. Init
32+
:param data: 语音信号数据
33+
:param fs: 采样率
34+
:param frameLen: 计算声压的时间长度(ms单位)
35+
:param isplot: 是否绘图,默认是
36+
:return: 返回声压列表spls
37+
"""
38+
39+
def spl_cal(s, fs, frameLen):
40+
"""
41+
根据数学公式计算单个声压值
42+
$y=\sqrt(\sum_{i=1}^Nx^2(i))$
43+
2020-2-26 Jie Y. Init
44+
:param s: 输入数据
45+
:param fs: 采样率
46+
:param frameLen: 计算声压的时间长度(ms单位)
47+
:return: 单个声压数值
48+
"""
49+
l = len(s)
50+
M = frameLen * fs / 1000
51+
if not l == M:
52+
exit('输入信号长度与所定义帧长不等!')
53+
# 计算有效声压
54+
pp = 0
55+
for i in range(int(M)):
56+
pp += (s[i] * s[i])
57+
pa = np.sqrt(pp / M)
58+
p0 = 2e-5
59+
spl = 20 * np.log10(pa / p0)
60+
return spl
61+
62+
length = len(data)
63+
M = fs * frameLen // 1000
64+
m = length % M
65+
if not m < M // 2:
66+
# 最后一帧长度不小于M的一半
67+
data = np.hstack((data, np.zeros(M - m)))
68+
else:
69+
# 最后一帧长度小于M的一半
70+
data = data[:M * (length // M)]
71+
spls = np.zeros(len(data) // M)
72+
for i in range(length // M - 1):
73+
s = data[i * M:(i + 1) * M]
74+
spls[i] = spl_cal(s, fs, frameLen)
75+
76+
if isplot:
77+
plt.subplot(211)
78+
plt.plot(data)
79+
plt.subplot(212)
80+
plt.step([i for i in range(len(spls))], spls)
81+
plt.show()
82+
return spls
83+
84+
85+
sb = soundBase('C2_3_y.wav')
86+
data, fs = sb.audioread()
87+
sb.SPL(data, fs)
88+
~~~
89+
### 声压级
90+
声音的有效声压与基准声压之比,取以10为底的对数,再乘以20,即为声压级,通常以符号$L_p$表示,单位为dB。
91+
$$L_p=20\lg\frac{P_e}{p_{ref}}(dB)$$
92+
93+
其中,$P_e$为待测声压的有效值,$P_{ref}$为参考声压,在空气中一般取$2\times 10^{-5}Pa$。
94+
95+
96+
97+
## 声强
98+
在物理学巾,声波在单位时间内作用在与其传递方向垂直的单位面积上的能量称为声强。日常生活中能听到的声音其强度范围很大,最大和最小之间可达$10^{12}$倍。
99+
### 声强级
100+
101+
用声强的物理学单位表示声音强弱很不方便。当人耳听到两个强度不同的声音时,感觉的大小大致上与两个卢强比值的对数成比例。因此,用对数尺度来表示声音强度的等级,其单位为分贝(dB) 。
102+
$$L_I=10\lg (I/I_0)(dB)$$
103+
104+
在声学中,$I_0=1\times 10^{-12}W/m^2$。
105+
### 声压与声强的关系
106+
对于球面波和平面波,声压与声强的关系是:
107+
$$I=P^2/(\rho·c)$$
108+
其中,$\rho$为空气密度,$c$为声速,在标准大气压和20摄氏度的环境下,$\rho·c=408 Pa·s/m$,这个数值叫国际单位值,也叫瑞丽,称为空气对声波的特性阻抗。
109+
110+
## 响度
111+
响度描述的是声音的响亮程度,表示人耳对声音的主观感受,其计量单位是宋。定义为声压级为40dB的1 kHz纯音的响度为1 Son (宋) 。人耳对声音的感觉,不仅和声压有关,还和频率有关。声压级相同,频率不同的声音,听起来响亮程度也不同。如空压机与电锯,同是100dB声压级的噪声,昕起来电锯声要响得多。按人耳对声音的感觉特性,依据卢压和频率定出人对声音的主观音响感觉量,称为响度级,单位为方,符号phon。根据国际协议规定,OdB声级的1000 Hz纯音的晌度级定义为0 phon。其他频率声音的声级与响度级的对应关系,要从等响度曲线才能查出。

0 commit comments

Comments
 (0)