首页 > 编程语言 >python WAV音频文件处理—— (1)读写WAV文件

python WAV音频文件处理—— (1)读写WAV文件

时间:2024-04-08 16:02:27浏览次数:26  
标签:python import PER wave file wav FRAMES WAV 音频文件

https://realpython.com/python-wav-files/#visualize-audio-samples-as-a-waveform

了解WAV文件格式

WAV是一种波形音频文件格式(Waveform Audio File Format)。虽然是一种古老的格式(九十年代初开发),但今天仍然可以看到这种文件。
WAV具有简单、可移植、高保真等特点。

WAV的波形

声音是一种波,可以用3个属性描述:

  • 振幅(Amplitude) 表示声波强度,可视为响度。
  • 频率(Frequency),波长的倒数,对应音高。
  • 相位(Phase)波开始时对应波周期中的位置。

如果你用音频软件(如Audacity)打开WAV文件,可能看到这样的波形
Audacity中的波形--振幅随时间变化

WAV 文件的结构

WAV 音频文件格式是一种二进制格式,结构如下:
WAV文件格式
Header 是一组元数据,描述了如何解释接下来的Frame。
Header中的参数说明:

  • Encoding:编码。样音频信号的数字表示。可用的编码类型包括未压缩的线性脉冲编码调制 (PCM) 和一些压缩格式,如 ADPCM、A-Law 或 μ-Law。
  • Channels:声道数。每帧中的声道数,对于单声道,通常等于 1 个,对于立体声音轨,通常等于 2 个,但对于环绕声录音,可能会更多。
  • Frame Rate:帧速率。也称采样率。
  • Bit Depth:位深度,每个音的比特位数。位深度越大,编码信号的动态范围越大,越能表现声音的细微差别。

为了忠实地表现音乐,大多数 WAV 文件使用立体声 PCM 编码,其中 16 位有符号整数以 44.1 kHz 采样。这些参数对应于标准 CD 质量的音频。巧合的是,这样的采样频率大约是大多数人能听到的最高频率的两倍。根据 Nyquist-Shannon 采样定理,这足以以数字形式捕获声音而不会失真。

Python的wave模块

wave 模块负责读取写入 WAV 文件(但不能播放声音)。

使用wave.open 读取wav文件将返回一个 wave.Wave_read object

import wave
with wave.open("Bongo_sound.wav") as wav_file:
    print(wav_file)

可以使用该对象检索存储在 WAV 文件Header信息并读取编码的音频帧

>>> with wave.open("Bongo_sound.wav") as wav_file:
...     metadata = wav_file.getparams() # header 
...     frames = wav_file.readframes(metadata.nframes) # frame
...

>>> metadata
_wave_params(
    nchannels=1,
    sampwidth=2,
    framerate=44100,
    nframes=212419,
    comptype='NONE',
    compname='not compressed'
)

>>> frames
b'\x01\x00\xfe\xff\x02\x00\xfe\xff\x01\x00\x01\x00\xfe\xff\x02\x00...'

>>> len(frames)
424838

读取的原始比特(bytes),我们需要手动解码。从Header中我们看到,每个音占2个字节(16位)。
我们可以用array模块:

>>> import array
>>> pcm_samples = array.array("h", frames)
>>> len(pcm_samples)
212419

或者使用struct模块:

>>> import struct
>>> format_string = "<" + "h" * (len(frames) // 2)
>>> pcm_samples = struct.unpack(format_string, frames)
>>> len(pcm_samples)
212419

<符号指示字节为小端格式(little-endian)。

numpy提供了更简单的方法:

>>> import numpy as np
>>> pcm_samples = np.frombuffer(frames, dtype="<h")
>>> normalized_amplitudes = pcm_samples / (2 ** 15)

numpy简洁高效,后面都使用numpy进行处理。

写WAV文件

从数学上讲,您可以将任何复杂声音表示为多个不同频率、振幅和相位的正弦波的总和。
正弦波
由于振幅A被缩放到[-1,1]之间,并且我们不关心相位,因此正弦波可以简化为:

import math

FRAMES_PER_SECOND = 44100

def sound_wave(frequency, num_seconds):
    for frame in range(round(num_seconds * FRAMES_PER_SECOND)):
        time = frame / FRAMES_PER_SECOND
        amplitude = math.sin(2 * math.pi * frequency * time)
        yield round((amplitude + 1) / 2 * 255)

现在,我们可以生成声音了。
下面我们生成一个频率为440Hz、持续2.5s的声音:

import math
import wave

...

with wave.open("output.wav", mode="wb") as wav_file:
    wav_file.setnchannels(1)
    wav_file.setsampwidth(1)
    wav_file.setframerate(FRAMES_PER_SECOND)
    wav_file.writeframes(bytes(sound_wave(440, 2.5)))

使用声音软件打开生成的文件,听到嘟的一声。

混合和立体声

为了合成立体声,
我们需要制造左右两个声道的声音,并在每一帧交替播放

import itertools
import math
import wave

FRAMES_PER_SECOND = 44100

def sound_wave(frequency, num_seconds):
    for frame in range(round(num_seconds * FRAMES_PER_SECOND)):
        time = frame / FRAMES_PER_SECOND
        amplitude = math.sin(2 * math.pi * frequency * time)
        yield round((amplitude + 1) / 2 * 255)

left_channel = sound_wave(440, 2.5)
right_channel = sound_wave(480, 2.5)
# 交替播放 两个声道
stereo_frames = itertools.chain(*zip(left_channel, right_channel)) 

with wave.open("output.wav", mode="wb") as wav_file:
    wav_file.setnchannels(2) # 2 channel
    wav_file.setsampwidth(1)
    wav_file.setframerate(FRAMES_PER_SECOND)
    wav_file.writeframes(bytes(stereo_frames))

或者,与其为声波分配单独的声道,不如将它们混合在一起以创建有趣的效果。
混合两种声音的效果等同于将两个声音的振幅相加

import math
import wave

FRAMES_PER_SECOND = 44100

def beat(frequency1, frequency2, num_seconds):
    for frame in range(round(num_seconds * FRAMES_PER_SECOND)):
        time = frame / FRAMES_PER_SECOND
        amplitude1 = math.sin(2 * math.pi * frequency1 * time)
        amplitude2 = math.sin(2 * math.pi * frequency2 * time)
        amplitude = max(-1, min(amplitude1 + amplitude2, 1))
        yield round((amplitude + 1) / 2 * 255)

with wave.open("output.wav", mode="wb") as wav_file:
    wav_file.setnchannels(1)
    wav_file.setsampwidth(1)
    wav_file.setframerate(FRAMES_PER_SECOND)
    wav_file.writeframes(bytes(beat(440, 441, 2.5)))

使用更高的位深度

到目前为止,您一直使用单个字节(8位)来表示每个音频样本,以保持简单。这为您提供了 256 个不同的振幅级别,足以满足您的需求。但是,您迟早会希望提高位深度,以实现更大的动态范围和更好的音质。

切换到更高的位深度时,必须相应地调整缩放字节转换。您可以使用 NumPy 优雅地表达声波方程并有效地处理字节转换:

import numpy as np
import wave

FRAMES_PER_SECOND = 44100

def sound_wave(frequency, num_seconds):
    time = np.arange(0, num_seconds, 1 / FRAMES_PER_SECOND)
    amplitude = np.sin(2 * np.pi * frequency * time)
    return np.clip(
        np.round(amplitude * 32768),
        -32768,
        32767,
    ).astype("<h")

left_channel = sound_wave(440, 2.5)
right_channel = sound_wave(480, 2.5)
stereo_frames = np.dstack((left_channel, right_channel)).flatten()

with wave.open("output.wav", mode="wb") as wav_file:
    wav_file.setnchannels(2)
    wav_file.setsampwidth(2) # 2 bytes == 16 bits 
    wav_file.setframerate(FRAMES_PER_SECOND)
    wav_file.writeframes(stereo_frames)

标签:python,import,PER,wave,file,wav,FRAMES,WAV,音频文件
From: https://blog.csdn.net/qq_41068877/article/details/137368450

相关文章

  • Python学习笔记-001
    记录一下重学python,虽然python老早就接触了,更多的还是停留在语法层面,老c++了。最近打算从头开始系统拉一下python的基础,先预计8天学完。后面还打算系统学一下Numpy,Pandas和Matplotlib。python基础教程python简介检查是否安装python,终端输入python--versionpython是一种解释......
  • python data:image/jpeg;base64为网址的图片改如何下载
    网址以data开头的文件,这里采用base64进行编码。它叫做dataURI scheme,是一种网页优化的手段。让我们直接把图像的内容崁入网页里面,减少页面的请求data:表示协议image/jpg:数据类型编码方式:base64可以通过解码的方式下载图片importbase64defdownload_auth_img(self,im......
  • Github图床 Python Typora
    1.搭建Github图床1.1.创建或者选择一个Public仓库1.2.获取GithubToken2.Typora结合图床当Typora需要使用这个图床的时候,Picgo是很好的解决方案,但是还可以通过其他的方式来进行上传,比如python脚本。2.1.upload-img.pyimportrequestsimportbase64importj......
  • python进阶之tkinter模块
    tkinter 是Python的标准图形用户界面(GUI)工具包,用于创建桌面应用程序的用户界面。tkinter 提供了一组丰富的组件和工具,使开发者能够轻松地构建具有按钮、标签、文本框、滚动条等元素的交互式应用程序。以下是 tkinter 模块的一些主要作用:创建窗口:tkinter 提供了创建窗口......
  • python计算机毕设【附源码】基于Android开发的智能音乐播放系统(django+mysql+论文)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:随着移动互联网的飞速发展,智能手机已经成为人们日常生活中不可或缺的一部分。在众多手机应用中,音乐播放系统是用户使用频率较高的应用之一。传统的音乐播放......
  • 文本转语音常用的几个python库
    在Python编程领域,文本到语音(Text-to-Speech,TTS)的转换是一个常见的需求,尤其是在开发能够与用户交互的应用程序时。以下是几个流行的Python库,它们可以帮助开发者实现文本到语音的转换,并且有的可以将转换后的语音保存为MP3文件。gTTS(GoogleText-to-Speech)gTTS是一个依......
  • 27岁自学Python转行靠谱吗?入行晚吗?
    今年已经奔三的小编来给大家说说,之前自己也是在一个普通的二本院校上学,学的还是工商管理,毕竟读书的时候电视剧里面的主角都是工商管理的大佬。不过在毕业之后就经历了社会的毒打,后面小编就想去换一个工作,学起了软件应用开发,然后这几年的数据分析很火又来试试,生命在于折腾......
  • 粉丝提问:26想转行做Python开发,是不是已经晚了?
    26岁基本上是一个硕士研究生刚毕业的年纪,相当于本科毕业工作了2年,总体来说时间耽误的并不算太多,想转行做Python开发,不算太晚!1转行前先想清楚这5点!①年龄:至少在35岁前还有9年时间,时间上面是可以的。②学历:有没有达到最低的学历要求?本科以下不好找。③风险:是否做好了......
  • 一起学习python——基础篇(7)
    今天讲一下python的函数。函数是什么?函数是一段独立的代码块,这块代码是为了实现一些功能,而这个代码块只有在被调用时才能运行。在Python中,使用 def关键字定义函数:函数的固定结构就是def(关键字)+函数名字(自己定义)+():deftest_function():#里面的内容一定要有空格(......
  • Python适用的工作,看看哪个适合你?
    学编程?Python?很多人可能一头雾水,觉得只有程序员才需要会编程,还把Python脑补得很难。其实不是的,Python在资源收集、数据分析、自动化办公等领域表现很突出,可以帮我们执行一些重复、低效的工作,让我们把更多时间花在刀刃上。并且,Python也不是程序员的专属,它将是每个职场人的......