需求
a和b通讯,两人都将通话进行录音,现在要计算两段录音的延迟
原理
录音会有静音片段,通过程序识别到静音片段(比如小于-40dB为静默),计算静音片段的开始和结束时间,两个录音的时间相减得到延迟。
系统环境,依赖库
python安装pydub
库。
电脑下载ffmpeg
,官网下载压缩包,解压后设置环境变量,将ffmpeg的...\bin
路径放到系统环境变量的PATH
下
使用ffmpeg -version
如果能发现版本信息输出,说明成功。
但是python程序仍然可能调用不了ffmpeg,下面代码中又手动设置了ffmpeg的路径。
下面的代码解析的是.wav
的音频文件,可以使用ffmpeg -i a.mp3 a.wav
先进行修改文件格式(不能强制修改拓展名!),也可以调AudioSegment.from_mp3
这个函数去处理.mp3
文件
代码
# E:\ffmpeg\ffmpeg-master-latest-win64-gpl\bin
# C:\\Users\\loneve\\Desktop\\a.mp3
import subprocess
from pydub import AudioSegment
from pydub.silence import detect_silence
from pydub import AudioSegment
import os
def detect_silence_periods(audio_file, file_name="Undefined", silence_thresh=-40, min_silence_len=1000):
print("计算文件:" + file_name + " 的静音片段")
# silence_thresh表示静音的阈值,小于这个dB的会被认为是静音
# min_silence_len表示静音最小时间段(毫秒为单位,小于这个时间段就认为不是静音)
# 加载音频文件
audio = AudioSegment.from_wav(audio_file)
# 检测静音片段,返回的是静音的开始和结束时间的列表
silence_periods = detect_silence(audio, min_silence_len=min_silence_len, silence_thresh=silence_thresh)
# 将时间单位从毫秒转换为秒
silence_periods = [(start / 1000.0, end / 1000.0) for start, end in silence_periods]
print(silence_periods)
return silence_periods
def calculate_delay(silence_periods_a, silence_periods_b):
# 假设静音片段在两个录音文件中的顺序一致
delays = []
for (start_a, end_a), (start_b, end_b) in zip(silence_periods_a, silence_periods_b):
delay_start = start_b - start_a
delay_end = end_b - end_a
delays.append((delay_start, delay_end))
# 平均计算得到的延迟
avg_delay_start = sum(delay[0] for delay in delays) / len(delays)
avg_delay_end = sum(delay[1] for delay in delays) / len(delays)
return avg_delay_start, avg_delay_end
def read_files(dic_path, file_format):
# 读取该路径下所有文件,放到一个list中
# 将该路径下所有文件通过ffmpeg转化成相应格式的文件,放到应该list中
print("读取中...")
print("===============")
converted_files = []
for file_name in os.listdir(dic_path):
file_path = os.path.join(dic_path, file_name)
output_file = os.path.splitext(file_path)[0] + f".{file_format}"
# ffmpeg转化文件格式
# command = f"ffmpeg -i \"{file_path}\" \"{output_file}\""
# subprocess.run(command, shell=True)
converted_files.append(file_path) # output_file
return converted_files
def handle_calculate(file_list):
for i in range(0, len(file_list), 2):
file1 = file_list[i]
file2 = file_list[i + 1] if i + 1 < len(file_list) else None
if file2:
print("开始处理 " + file1.split("\\")[-1] + " " + file2.split("\\")[-1] + ": ")
# 处理逻辑
# 检测静音片段
silence_a = detect_silence_periods(file1, file1.split("\\")[-1])
silence_b = detect_silence_periods(file2, file2.split("\\")[-1])
# 计算平均延迟
avg_delay_start, avg_delay_end = calculate_delay(silence_a, silence_b)
print(f"平均延迟开始: {avg_delay_start} 秒")
print(f"平均延迟结束: {avg_delay_end} 秒")
print("===============")
else:
print(file1.split("\\")[-1] + "没有文件与之对比!")
# 手动设置ffmpeg路径
AudioSegment.ffmpeg = r"E:\ffmpeg\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe"
AudioSegment.converter = r"E:\ffmpeg\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe"
# 读入数据,要处理的文件夹路径
dic_path = r"E:\audios"
file_format = "wav"
try:
files = read_files(dic_path, file_format)
if len(files) % 2 != 0:
print("文件分组失败!")
else:
handle_calculate(files)
except FileNotFoundError:
print("未找到文件!")
else:
print("success")
'''
# 示例文件路径
# 注意,源文件格式如果是.m4a,就要使用ffmpeg -i a.m4a a.wav 进行格式转换,不能直接重名名修改拓展名来修改,这样会解码错误。
audio_file_a = r'E:\PythonProgram\pythonProject\mp3\d.wav'
audio_file_b = r'E:\PythonProgram\pythonProject\mp3\e.wav'
# 检测静音片段
silence_periods_a = detect_silence_periods(audio_file_a, audio_file_a.split("\\")[-1])
silence_periods_b = detect_silence_periods(audio_file_b, audio_file_b.split("\\")[-1])
# 计算延迟
avg_delay_start, avg_delay_end = calculate_delay(silence_periods_a, silence_periods_b)
print(f"平均延迟开始: {avg_delay_start} 秒")
print(f"平均延迟结束: {avg_delay_end} 秒")
'''