跳转至

pydub音频库使用简介

音频处理库pydub的使用实例。

安装pydub

使用pip安装即可(还需安装ffmpeg依赖,建议使用conda命令安装,则不需要配置环境):

$ pip3 install pydub

基本用法

1、导入和读取音频文件

from pydub import AudioSegment
audio = AudioSegment.from_file("path/to/file")

# 其他方法
song = AudioSegment.from_wav("never_gonna_give_you_up.wav")
song = AudioSegment.from_mp3("never_gonna_give_you_up.mp3")

ogg_version = AudioSegment.from_ogg("never_gonna_give_you_up.ogg")
flv_version = AudioSegment.from_flv("never_gonna_give_you_up.flv")

mp4_version = AudioSegment.from_file("never_gonna_give_you_up.mp4", "mp4")
wma_version = AudioSegment.from_file("never_gonna_give_you_up.wma", "wma")
aac_version = AudioSegment.from_file("never_gonna_give_you_up.aiff", "aac")

音频保存/转换格式

audio.export("path/to/new/file", format="mp3")

# tags参数,是保存 歌曲ID3 tag信息的
audio.export("mashup.mp3", format="mp3", tags={'artist': 'Various artists', 'album': 'Best of 2011', 'comments': 'This album is awesome!'})

2、播放音频

from pydub.playback import play
play(audio)

3、音频时长

# 读取时长
duration = audio.duration_seconds # 单位为秒

# 设置时长

4、调整音量

+6 就表示将音乐的音量提高6分贝,-10就表示将音乐的音量降低10分贝

# 增加10分贝
louder_audio = audio + 10

# 减小10分贝
quieter_audio = audio - 10

5、音频切割

pydub中的标准时间为毫秒,

# 前10秒
audio = audio[:10000]

# 后10秒
audio = audio[-10000:]

# 从第10秒开始到第20秒结束
audio = audio[10000:20000]

# 从第10秒开始到结尾
audio = audio[10000:]

6、音频合并

audio1 = AudioSegment.from_file("path/to/file1")
audio2 = AudioSegment.from_file("path/to/file2")
audio_combined = audio1 + audio2

# 用于生成一个长度为0的AudioSegment对象,一般用于多个音频的合并。
play_list = AudioSegment.empty()
play_list += sound1
play_list += sound2

# 产生一个持续时间为10s的无声AudioSegment对象
ten_second_silence = AudioSegment.silent(duration=10000)

7、重复播放

audio = AudioSegment.from_file("path/to/file")
repeat = audio * 2
play(repeat)

8、将音乐翻转(reverse)

# song is not modified
# AudioSegments are immutable
backwards = audio.reverse()

9、音频等分切割的例子

下面是一段完整的代码,用于对音频进行前后切割,并将音频分割成合适长度的小段进行保存。

from pydub import AudioSegment

# 读取音频文件
audio = AudioSegment.from_file("path/to/file")

# 输出视频时长
print('视频时长:', audio.duration_seconds / 60)

# 前后切割
start = int(input('前切割n秒,不切割输入0'))*1000
end = int(input('后切割n秒,不切割输入0'))*1000
if start:
    audio = audio[start:-end]

# 计算合适的分割长度
for i in range(1, 1000):
    if 3.3 >= (audio.duration_seconds / (60 * i)) >= 2.8:
        number = i
        break
chunks = audio[::int(audio.duration_seconds / number * 1000 + 1)]

# 保存分割后的音频
for i, chunk in enumerate(chunks):
    print('分割后的时长:', chunk.duration_seconds / 60)
    chunk.export("path/to/new/file{}.wav".format(i), format="wav")

10、制作铃声

from pydub import AudioSegment

# 读取音频文件
audio = AudioSegment.from_file("path/to/file")

# 切割并保存
start = 10000
end = 15000
ringtone = audio[start:end]
ringtone.export("path/to/new/file", format="mp3")

音频属性

1、声道分离

# 声道的分离,得到两个不同声道对应的 AudioSegment 对象
left_channel, right_channel = audio.split_to_mono()

2、获取音频的某一帧

audio.get_frame(1)  # 获取第一帧

3、获取音频属性

下面我们来获取音频的一些属性,不过在获取之前,先介绍一下音频属性的一些细节。

采样频率:又被称作取样频率,是单位时间内的采样次数,决定了数字化音频的质量。采样频率越高,数字化音频的质量越好,还原的波形越完整,播放的声音越真实,当然所占的大小也就越大。根据奎特采样定理,要从采样中完全恢复原始信号的波形,采样频率要高于声音中最高频率的两倍。人耳可听到的声音的频率范围是在 16 赫兹到 20 千赫兹之间,因此要将听到的原声音真实地还原出来,采样频率必须大于 40千赫兹。而 44千赫兹 的音频可以达到 CD 的音质,当然可以更高,只不过高于 48 千赫兹 的采样频率人耳很难分别,没有实际意义。

采样位数:也叫量化位数(单位:比特),是存储每个采样值所用的二进制位数,采样值反映了声音的波动状态,采样位数决定了量化精度。采样位数越长,量化的精度就越高,还原的波形曲线越真实,产生的量化噪音越小,回放的效果越真实。常用的量化位数有 4、8、12、16、24等等,量化位数与声卡的位数和编码有关。

声道数:使用的声音通道的个数,也是采样时所产生的声音波形个数。播放声音时,单声道的 wav 一般使用一个喇叭发声,立体声的 wav 可以使用两个喇叭发声。记录声音时,单声道每次产生一个波形的数据;双声道每次产生两个波形的数据,当然最终音频所占的存储空间也会增加一倍。

比特率:比特率是指每秒传送的比特(bit)数,单位为 bps(Bit Per Second),比特率越高,传送的数据越大。在音频、视频领域,比特率又被称为码率、位率、位速(这四个老铁是同一个东西,只是不同领域、不同翻译造就了这么多的名词)。比特率表示经过编码(压缩)后的音、视频数据每秒钟需要用多少个比特来表示。比特率与音、视频压缩的关系,简单来说就是比特率越高,音频、视频的质量就越好,但编码后的文件就越大;如果比特率越少则情况刚好相反,比特率 = 采样频率 * 采样位数 * 声道数。

from pydub import AudioSegment

song = AudioSegment.from_mp3("高梨康治 - 百鬼夜行.mp3")

# 声道数, 1 表示单声道, 2 表示双声道
print(song.channels)  # 2

# 采样宽度, 采样位数除以 8 就是采样宽度了, 因为一个字节有 8 位
# 同理采样宽度乘以 8 就是采样位数,当前音频是 16 位的
print(song.sample_width)  # 2
print(song.sample_width * 8)  # 16

# 采样频率, 采样频率等于帧速率
print(song.frame_rate)  # 44100

# 块对齐之后的大小, 或者一帧的字节数
# 等于 通道数 * 采样位数 / 8, 或者 通道数 * 采样宽度
print(song.frame_width)  # 4
print(song.channels * song.sample_width)  # 4

# 字节率, 等于 采样频率 * 声道数量 * 采样宽度(采样位数 / 8), 可以直接计算得到
print(song.frame_rate * song.channels * song.sample_width)  # 176400

# 时长(单位秒)
print(song.duration_seconds)  # 87.8225850340136

# 帧数目
print(song.frame_count())  # 3872976.0

4、获取原始的音频数据

raw_data 属性返回原始音频数据,为wav格式的数据,字节流的形式存储。使用时转换为数组处理。多个声道的存储格式。举个例子,双声道音频会像这样: [sample_1_L, sample_1_R, sample_2_L, sample_2_R, …]

get_array_of_samples 以采样数组的形式返回原始音频数据。注意:如果音频有多个声道,每个声道的采样会被连起来存放 – 举个例子,双声道音频会像这样: [sample_1_L, sample_1_R, sample_2_L, sample_2_R, …]

# 原始的音频数据,
song.raw_data

# 获取原始数据,字符串类型
wave_string = song.raw_data
wave_data = np.frombuffer(wave_string, dtype=np.int16)  # 将字符串转化为int

# 多通道数据,转换为channels列的 多维数组
if channels > 1:
    # 原始数据为 [1, 2, 3, 4, 5, 6]
    # 转换为 channels=2 列的数组,[[1,2],[3,4],[5,6]]
    wave_data = wave_data.reshape((-1, channels))

    # 获取第一个声道数据 [1,3,5]
    wave_1 = wave_data[:, 0]

    # 获取第 二个声道数据 [2,4,6]
    wave_1 = wave_data[:, 1]

# 以采样数组的形式返回原始音频数据
wave_array = audio.get_array_of_samples()

5、修改音频属性

# 将通道设置为 1, 改为单声道,然后导出
song.set_channels(1).export("高梨康治 - 百鬼夜行_1.mp3", "mp3")

采样频率等于帧速率,以赫兹为单位。增大这个值通常不会导致质量的下降,但降低这个值一定会导致质量的下降,因为更高的帧速率意味着更大的频响特征(即可以表示更高的频率)。

print(song.frame_rate)  # 44100

# 更改采样频率, 一般都是 44100, 我们可以修改为其它的值
# 注意: 并不是任意值都可以, 只能是 8000 12000 16000 24000 32000 44100 48000 之一
# 如果不是这些值当中的一个, 那么会当中选择与设置的值最接近的一个
# 比如我们设置 18000, 那么会自动变成 16000
song.set_frame_rate(18000).export("高梨康治 - 百鬼夜行_1.mp3", "mp3")
print(
    AudioSegment.from_mp3(r"高梨康治 - 百鬼夜行_1.mp3").frame_rate
)  # 16000

还可以设置采样宽度(采样位数除以 8),对于一个音频而言能设置这些属性已经足够了。像很多大厂提供的音频识别服务,也会对音频属性有严格的限制,而限制的属性也基本上就这些。无非是通道、采样频率、采样位数等等。

from pydub import AudioSegment

song = AudioSegment.from_mp3("高梨康治 - 百鬼夜行.mp3")
print(song.sample_width)  # 2
song.set_sample_width(3).export("高梨康治 - 百鬼夜行_1.mp3", "mp3")
print(
    AudioSegment.from_mp3(r"高梨康治 - 百鬼夜行_1.mp3").sample_width
)  # 2

从打印的结果上来看,我们似乎没有设置成功,因为这和音频本身也是有相应关系的。可能音频本身的采样宽度就只能是 2,不过绝大部分音频的采样宽度都是 2,即采样位数为 16。

高级用法

还可以通过pydub对音频进行编解码、混音、重采样等操作.

1、编解码

from pydub import AudioSegment

# 读取音频文件
audio = AudioSegment.from_file("path/to/file")

# 编码
encoded_audio = audio.set_frame_rate(16000).set_sample_width(2).set_channels(1)

# 解码
decoded_audio = encoded_audio.set_frame_rate(44100).set_sample_width(4).set_channels(2)

2、混音

在进行音频混音操作时,需要保证两个音频文件的采样率、采样位数和声道数相同。

from pydub import AudioSegment

# 读取音频文件
audio1 = AudioSegment.from_file("path/to/file1")
audio2 = AudioSegment.from_file("path/to/file2")

# 混音
mixed_audio = audio1.overlay(audio2)

# 保存混音后的音频
mixed_audio.export("path/to/new/file", format="wav")

3、重采样

from pydub import AudioSegment

# 读取音频文件
audio =AudioSegment.from_file("path/to/file")

# 重采样为44100Hz
resampled_audio = audio.set_frame_rate(44100)

# 保存重采样后的音频
resampled_audio.export("path/to/new/file", format="wav")

4、音频拼接设置

fade in and fade out淡入、淡出,就是逐渐增强与逐渐减弱

crossfade(交叉过度) 就是让一段音乐平缓地过渡到另一段音乐,上面的crossfade = 1500 表示过渡的时间是1.5秒。

audio =AudioSegment.from_file("path/to/file")
seg   =AudioSegment.from_file("path/to/file2")

# 淡入、淡出, 逐渐增强2秒,逐渐减弱3秒
audio_fade = audio.fade_in(2000).fade_out(3000)

# crossfade(交叉过度),1.5 second
audio_with_style = audio.append(seg, crossfade=1500)

# 加速减速
song = audio._spawn(audio.raw_data, overrides={"frame_rate": int(audio.frame_rate * 1.4)}).set_frame_rate(audio.frame_rate)

案例

1、案例1:通过识别空白音,分割音频中的歌曲

from pydub import AudioSegment
from pydub.silence import split_on_silence

# 读取音频文件
audio = AudioSegment.from_file("audio.mp3", format="mp3")

# 设置分割参数
min_silence_len = 700  # 最小静音长度
silence_thresh =-10  # 静音阈值,越小越严格
keep_silence = 600  # 保留静音长度

# 计算分割数量
num_segments = int(audio.duration_seconds/60/3)  # 每首歌曲大概三分钟,计算歌曲数量

# 分割音频文件
for i in range(-10, 0):
    segments = split_on_silence(audio, min_silence_len=min_silence_len, silence_thresh=i, keep_silence=keep_silence)
    if len(segments) <= num_segments:
        print(f"分割成功,共分割出 {len(segments)} 段")
        break
    else:
        print(f"当前阈值为 {i},分割出 {len(segments)} 段,继续尝试")

首先,我们使用AudioSegment.from_file()方法读取音频文件,并设置分割参数min_silence_len、silence_thresh和keep_silence分别表示最小静音长度、静音阈值和保留静音长度。其中,静音阈值越小,分割出的小段越多,但可能会出现误分割的情况;反之,静音阈值越大,分割出的小段越少,但可能会出现漏分割的情况。

然后,我们计算分割数量num_segments,即将音频文件分割成多少段。这里我们假设每首歌曲大概三分钟,计算出总共需要分割成多少段。

最后,我们使用split_on_silence()方法对音频文件进行分割,设置分割参数,并通过循环来不断调整静音阈值,直到分割出的小段数量符合预期为止。如果分割成功,则跳出循环;否则,继续尝试。

总而言之,pydub是一个非常实用的音频处理库,可以方便地进行音频处理、转换、合并等操作。同时,pydub还有丰富的应用场景,如制作铃声、调整音量等。值得注意的是,在使用pydub的过程中,需要注意音频格式的兼容性问题。

总结一下pydub的优点和缺点。

优点:

轻量级:pydub是一个轻量级的音频处理库,安装方便,使用简单。

功能丰富:pydub提供了丰富的音频处理功能,包括切割、合并、转换、调整音量、编解码、混音、重采样等。

应用广泛:pydub的应用场景非常广泛,包括音频处理、铃声制作、音频格式转换、语音识别等等。

缺点:

对格式的兼容性有限:pydub对音频格式的兼容性有限,不支持所有的音频格式,需要先将音频转换为支持的格式后才能进行处理。

性能一般:pydub在处理大文件时,性能可能会比较一般,需要耗费一定的时间和计算资源。

不支持流式处理:pydub不支持流式处理,需要将整个音频文件读取到内存中,导致内存占用较大。

综上所述,pydub是一个功能丰富、应用广泛的音频处理库。在使用pydub时,需要注意音频格式的兼容性问题,并注意处理大文件时的性能和内存占用。如果需要处理更复杂的音频任务,可以考虑使用其他更专业的音频处理库。