python要产生波形肯定是数字波形了
而我们听到的音乐的频率则是模拟频率。
模拟频率和数字频率之间的关系由采样率决定
我们先来尝试生成一个模拟频率为100Hz的正弦波,采样率22050Hz,那么其数字域的周期应该是采样率除以模拟频率
S a m p l e _ R a t e / A n a l o g _ F r e q u e n c e Sample\_Rate / Analog\_Frequence Sample_Rate/Analog_Frequence
数字角频率则是
ω = 2 π T d i g i t a l \omega = \frac{2\pi}{T_{digital}} ω=Tdigital2π
如果我们的采样时间为t,则采样点数为
N = t × S a m p l e _ R a t e N = t \times Sample\_Rate N=t×Sample_Rate
ok根据以上知识我们先来产生一个数组
import numpy as np
from numpy import pi
import matplotlib.pyplot as plt
import wave
sample_rate=22050 # 采样率
fa = 100 # 模拟频率
T = sample_rate / fa #周期
D_Omega = 2*pi/T # 数字角频率
t_length = 10 # 音频时长,秒
D_num = t_length * sample_rate# 对应的数字波形点数
x = np.arange(0,D_num)
y = np.sin(D_Omega * x)
尝试绘制一下这个波形,如下添加时间轴数组(让横轴显示的是模拟信号的真实时间)
t = x/sample_rate
plt.plot(t,y) #画出一个周期的波形图
plt.show()
可以绘制出来音频的波形图,放大某一区域可以看到其周期为0.01s,也就是频率为100Hz
向wav文件写入用wav的库就很简单了
file=wave.open(r'wave.wav','wb')
file.setnchannels(1)#设置通道数
file.setsampwidth(2)#设置采样宽
file.setframerate(sample_rate)#设置采样
file.setcomptype('NONE','not compressed')#设置采样格式 无压缩
按如上方式设置保存音频的通道数、采样宽、采样率等等,就完成了相关的配置。
参考官方文档可知,
Wave_write.setnchannels(n)
设置声道数。(1 为单声道,2 为立体声)
Wave_write.setsampwidth(n)
设置采样字节长度为 n。
Wave_write.setframerate(n)
设置采样频率为 n。
Wave_write.setcomptype(type, name)
设置压缩格式。目前只支持 NONE 即无压缩格式。
接下来向文件中写入波形,首先要将数据转换成字节码,然后再写,官方文档中有
Wave_write.writeframes(data)
写入音频帧并确保 nframes 是正确的。
因此我们将数组里的数值映射到整型数的整个区间,再写入文件中。
y=y*32768
y_data=y.astype(np.int16).tobytes()#将类型转为字节
file.writeframes(y_data)
file.close()
接下来用一个叫wave editor的软件查看波形
wave editor波形查看软件
百度云地址 提取码: jht6
接下来把波形生成、写入文件这些封装成函数。
我们每次生成波形需要的参数有模拟频率、采样率、时间长度以及波形,以此作为函数参量。
def createWave(sample_rate= 22050,fa = 100,t_length = 10,mode="square25"):
T = sample_rate / fa #周期
D_Omega = 2*pi/T # 数字角频率
D_num = int(t_length * sample_rate)# 对应的数字波形点数
x = np.arange(0,D_num)
y = np.ones(D_num)
# 基波
if mode == "square125": # 方波占空比12.5%
high = T//8
y[x%T > high] = -1
elif mode == "square25": # 方波占空比25%
high = T//4
y[x%T > high] = -1
elif mode == "square50": # 方波占空比50%
y = np.sin(D_Omega * x)
y[y>0] = 1
y[y<0] = -1
elif mode == "square75": # 方波占空比75%
high = 3*T//4
y[x%T > high] = -1
elif mode == "triangle": # 三角波
for i in range(len(x)):
y[i] = abs(1-i%T/T*2)
y = y - 1 # 向下平移
elif mode == "noise": # 噪声
y = np.random.normal(0,1,D_num) ## 我也不知道应该是什么分布的噪声,先用这个吧
t = x/sample_rate
return y,t
接下来试着生成这五种波形看看
if __name__ == "__main__":
mode = ["square125","square25","square50","square75","triangle","noise"]
for i in range(6):
y,t = createWave(sample_rate= 22050,fa = 100,t_length = 0.05,mode=mode[i])
plt.subplot(2,3,i + 1)
plt.plot(t,y) #画出一个周期的波形图
plt.show()
有
接下来是保存波形的函数
def saveWave(y,sample_rate,path = r'wave.wav'):
file=wave.open(path,'wb')
file.setnchannels(1)#设置通道数
file.setsampwidth(2)#设置采样宽
file.setframerate(sample_rate)#设置采样
file.setcomptype('NONE','not compressed')#设置采样格式 无压缩
y=y*32768
y_data=y.astype(np.int16).tobytes()#将类型转为字节
file.writeframes(y_data)
file.close()
我试了试把几个波形叠加起来保存
结果大概是这样的