Python工具箱系列(六十二)
对录音文件进行操作
在参加会议、论坛时经常会有录音的需求。但限于条件,经常会出现录音的声音小需要增强,无关内容需要剪切等需求。此时,就需要对音频文件进行变换。以下代码演示了部分变换功能。
from pydub import AudioSegment
from pydub.silence import detect_silence, detect_nonsilent
from pathlib import Path
import glob
import matplotlib.pyplot as plt
import librosa
import librosa.display
from librosa.display import waveshowdef add_silence(audiofilename, silence_length, output_file):"""给音频文件头增加一段静音Args:audiofilename (string): 音频文件名silence_length (int): 静音的秒数output_file (string): 输出的音频文件名"""one_sec_segment = AudioSegment.silent(duration=silence_length*1000)sound = AudioSegment.from_file(audiofilename)final_song = one_sec_segment + soundfinal_song.export(output_file, format="wav")def cut(audiofilename, start, duration, outputfilename):"""从音频文件中切割一段并且输出为文件Args:audiofilename (string): 音频文件名start (int): 开始时间(秒)duration (int): 持续时间(秒)output_file (string): 输出的音频文件名"""sound = AudioSegment.from_file(audiofilename)print(sound.duration_seconds, sound.dBFS, sound.frame_rate)cutstart = start*1000cutend = (start+duration)*1000clip = sound[cutstart:cutend]clip.export(outputfilename)def cutbynonesilent(audiofilename):"""从音频文件中切割所有非静音段,并且输出成系列文件Args:audiofilename (string): 音频文件名"""sound = AudioSegment.from_file(audiofilename)# 非静音检测,按最少2秒,-50DB为分隔标准start_end_list = detect_nonsilent(sound, 2000, -50, 1)# 将非静音时段的音频单独输出pth = Path(audiofilename)for index, seg in enumerate(start_end_list):# 组合输出文件名outputfilename = Path.joinpath(pth.parent, f'{pth.stem}-{index}.wav')clip = sound[seg[0]:seg[1]]clip.export(outputfilename)def continuous_mix(filelist, outputfilename):"""串烧Args:filelist (list): 要串烧的文件列表outputfilename (string): 输出文件"""one_sec_segment = AudioSegment.silent(duration=2*1000)mixer = AudioSegment.from_file(filelist[0])for file in filelist[1:]:# 在头上合成时加入一段静音进行分隔。clip = AudioSegment.from_file(file)mixer = mixer + one_sec_segment + clip# 渐入与渐出mixer.fade_in(1000).fade_out(1000)mixer.export(outputfilename)def volum(audiofilename,factor):"""放大或者缩小音量Args:audiofilename (string): 音频文件名factor (int): 正值为放大的分贝数,负值为缩小的分贝数"""pth = Path(audiofilename)outputfilename = Path.joinpath(pth.parent, f'{pth.stem}-gain{pth.suffix}')sound = AudioSegment.from_file(audiofilename)sound += factorsound.export(outputfilename)def test_mixer():# 串烧指定目录下的所有MP3文件globfiles = glob.iglob(r'd:\test\mp3\*.mp3')continuous_mix(list(globfiles), r'd:\test\done\mixer.mp3')def test_cut():targetfilename = r'D:\test\m4a\1.m4a'cut(targetfilename, 10, 20, r'd:\test\cut1.wav')cutbynonesilent(targetfilename)def test_volum():originaudio = r'D:\test\m4a\1-0.wav'changedaudio = r'D:\test\m4a\1-0-gain.wav'volum(originaudio,20)# plt.figure(figsize=(15,17))fig, ax = plt.subplots(nrows=2, sharex=True)origin ,sr = librosa.load(originaudio)librosa.display.waveshow(origin,sr=sr,ax=ax[0])ax[0].set(title='origin audio wave')ax[0].label_outer()changed ,sr = librosa.load(changedaudio)librosa.display.waveshow(changed,sr=sr,ax=ax[1])ax[1].set(title='changed audio wave')ax[1].label_outer()plt.show()test_mixer()
test_cut()
test_volum()
上述代码中:
综合使用了librosa/pydub两种声音处理库,各取所长。librosa能够在更底层处理音频文件,进行各类变换。
add_silence函数对指定的音频文件进行加工,在头部加入一段静音。
cut函数对于指定的音频文件进行切割,能够将其中一段音频切出来后存为另一个音频文件。
cutbynonesilent函数对于指定的音频文件进行切割,能够将非静音部分切割为不同的文件。这个功能对于录音来说非常必要。在现实的录音中,有可能存在大段的静音。切割后,可以针对每部分进行语音的加工(放大音量、语音转文字等)。
continuous_mix函数是一个串烧的函数,能够将输入的文件列表中的文件依次合成在一起。形成一个串烧的效果,并且加入了静音,以及渐入渐出效果
volum函数对音频文件进行音量的增强与衰减。
最后再整理一下安装过程:
pip install pyaudio
pip install pydub
pip install librosa
pip install matlibplot
代码中列出的MP3/WAV文件可以随便替换,不必纠结。