Python 从零开始制作自己的声音

您所在的位置:网站首页 邵阳市开元职业中专学校 Python 从零开始制作自己的声音

Python 从零开始制作自己的声音

2024-07-12 20:57:39| 来源: 网络整理| 查看: 265

计算机经常被用于处理音频这种真实世界中的数据。声音经过采样,量化和编码后,存储在音频文件,如wav文件中。 文章首先介绍wave模块的基础用法; 再通过生成一定频率声波的算法实现,来深入讲解wave库的使用。

目录 wave模块wave.open()Wave_readWave_write初步: 拼接音频 初次实现再次实现

wave模块

wave模块提供了一个处理 wav 声音格式的便利接口, 可获取wav文件头信息, 从文件读取数据, 也可直接将bytes格式的数据写入wav文件。

wave.open()

wave.open(file, mode=None) 类似于普通的打开文件,函数接收两个参数,file为文件名或文件对象,mode可取"r",“rb”,“w”,“wb"四个值,其中"r"和"rb”, "w"和"wb"效果完全相同。如下:

>>> wave.open('音乐.wav','r') >>> wave.open('test.wav','w')

以读模式打开的文件会返回Wave_read 对象, 写模式打开时会返回Wave_write 对象。

Wave_read

Wave_read 对象通过wave.open() 函数创建。wave文件记录了二进制的音频数据,由许多帧组成,一个采样对应一个帧,每一帧长度为1或2字节。

Wave_read.getnchannels():返回声道数量(1 为单声道,2 为立体声)

Wave_read.getsampwidth():返回采样字节长度 (每一帧的字节长度)。

Wave_read.getframerate():返回采样频率。

Wave_read.getnframes():返回音频总帧数。

Wave_read.getcomptype()和Wave_read.getcompname():返回压缩类型。

Wave_read.readframes(n) 读取并返回以 bytes 对象表示的最多 n 帧音频。

Wave_read.tell() 返回当前文件指针位置。

Wave_read.setpos(pos) 设置文件指针到指定位置。

Wave_write

Wave_write 对象也通过wave.open() 函数创建。

Wave_write.setnchannels(n):设置声道数。

Wave_write.setsampwidth(n):设置采样字节长度为 n。

Wave_write.setframerate(n):设置采样频率为 n。

Wave_write.setnframes(n):设置总帧数为 n。(后来发现调用writeframes()时,wave模块会自动更新总帧数,实际上不需要调用这个函数)

Wave_write.setcomptype(type, name):设置压缩格式。(目前只支持 NONE 即无压缩格式。)

Wave_write.tell() 返回当前文件指针,其指针含义和 Wave_read.tell() 以及 Wave_read.setpos() 是一致的。

Wave_write.writeframes(data)(或writeframesraw(data)) 写入bytes格式的音频帧,并更新 nframes。

Wave_write.close() 确保 nframes 是正确的,并在文件被 wave 打开时关闭它。 此方法会在对象收集时被调用。 如果输出流不可查找且 nframes 与实际写入的帧数不匹配时引发异常。

初步: 拼接音频

程序先将两段音频中的数据读入data1和data2中,再将读取的数据拼接,写入result.wav。注意两段音频的采样频率、采样字节长度需要一致。

import wave sampwidth = 1 framerate = 22050 with wave.open('音乐1.wav','rb') as f1: sampwidth = f1.getsampwidth() framerate = f1.getframerate() nframes1=f1.getnframes() data1=f1.readframes(nframes1) with wave.open('音乐2.wav','rb') as f2: nframes2=f2.getnframes() data2=f2.readframes(nframes2) with wave.open('result.wav','wb') as fw: fw.setnchannels(1) fw.setsampwidth(sampwidth) fw.setframerate(framerate) #fw.setnframes(nframes1+nframes2) fw.writeframesraw(data1) fw.writeframesraw(data2) 初次实现

现在开始制作自己的声音。程序生成一段频率为200Hz, 长度为1.8秒的蜂鸣声。

import wave from winsound import PlaySound,SND_FILENAME file = 'test.wav' len_= 1.8 # 秒 frequency = 200 sampwidth = 1 #每一帧宽度(采样字节长度) framerate = 22050 # 采样频率 (越大音质越好) length = int(framerate * len_ * sampwidth) para = [0b00000000]*(framerate//frequency//2*sampwidth)\ +[0b11111111]*(framerate//frequency//2*sampwidth) # 音频的一小段 data=bytes(para) # 生成wav文件 with wave.open(file,'wb') as f: f.setnchannels(1) f.setsampwidth(sampwidth) f.setframerate(framerate) # f.setnframes(length) (可选) f.writeframes(data * (length // len(data))) PlaySound(file,SND_FILENAME) # 播放生成的wav 再次实现

上述程序生成的是方波,并有一些缺陷,如para中0b0000000和0b11111111的长度是整数且相同,导致生成的声音频率不精确,等等。 这里合成一段200Hz,长度为1.8秒的正弦波。

import wave,math from winsound import PlaySound,SND_FILENAME def generate(T,total,volume,sine=False): # T: 周期, total 总长度, 都以帧为单位 if not sine: h = T / 2 for i in range(total): if i % T >= h: yield volume else: yield 0 else: # 计算方法: sin 的 T = 2*pi / w w = 2 * math.pi / T; r = volume / 2 for i in range(total): yield int(math.sin(w * i) * r + r) file = 'test.wav' len_= 1.8 # 秒 frequency = 200 sampwidth = 1 framerate = 22050 sine=True volume = 255 # 音量, 0 - 255 data = bytes(generate(framerate / frequency, int(framerate*len_), volume,sine)) # bytes能接收0-255整数型的迭代器 with wave.open(file,'wb') as f: f.setnchannels(1) f.setsampwidth(sampwidth) f.setframerate(framerate) f.writeframes(data) PlaySound(file,SND_FILENAME)

运行程序会发现,正弦波听起来比方波更加柔和。 自己做的合成与Python内置的音频合成对比:

import winsound # Beep(freq,duration),参数分别是频率和毫秒为单位的持续时间 winsound.Beep(200,1800)

发现, 前述程序很好地仿真了调用内置的Beep函数发声。 但音质有区别, 这是采样字节长度为1(只有8位)导致的, 还需要加大采样字节长度。 最终的程序如下:

import wave,math,struct from winsound import PlaySound,SND_FILENAME def generate(T,total,volume,sampwidth,sine=False): # T: 周期, total 总长度, 以帧为单位 volume = min(volume * 2**(sampwidth*8),2**(sampwidth*8) - 1) if not sine: h = T / 2 for i in range(total): if i % T >= h: yield volume else: yield 0 else: w = 2 * math.pi / T; r = volume / 2 for i in range(total): # T = 2*pi / w yield int(math.sin(w * i) * r + r) file = 'test.wav' len_= 1.8 # 秒 frequency = 200 sampwidth = 2 framerate = 22050 sine=True volume = 255 # 8位的wav文件的一帧是无符号8位整数, 而16位的一帧是有符号的整数(-32768至32767)。 if sampwidth == 1: # 8位 lst = list(generate(framerate / frequency, int(framerate*len_), volume,sampwidth,sine)) data = bytes(lst) elif sampwidth == 2: data = b'' # 16位 lst = list(generate(framerate/frequency, int(framerate*len_), volume,sampwidth,sine)) for digit in lst: data += struct.pack('


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭