# -*- coding: utf-8 -*-
#/usr/local/bin/python3
# @Time : 2020/3/7 4:05 PM
# @Author : eric
# @File : get_audio_loudness.py
# @Software: PyCharm
import os
import re
import subprocess
import sys
import csv
'''
说明:
Integrated loudness:
I(整体响度): -26.5 LUFS
Threshold: -37.1 LUFS
Loudness range:
LRA(整体范围): 10.2 LU
Threshold: -49.5 LUFS
LRA low: -36.9 LUFS
LRA high: -26.6 LUFS
mean_volume(平均音量): -32.2 dB
max_volume(最大音量): -18.9 dB
'''
'''
:param '/Users/yy/Documents/test_noise/agc/android_new/test_saopin_32bit.wav'
:return {'I': '-26.5', 'LRA': ' 10.2', 'Threshold': '-49.5', 'LRA_low': '-36.9', 'LRA_high': '-26.6', 'mean_volume': '-32.2', 'max_volume': '-18.9'}
# 音频整体响度/音量获取方法,输出文件
'''
def get_audio_loudness_by_file(audiofile):
lufs_I = r"\s+I:\s+([-+\s]\d+\.\d) LUFS"
lufs_Threshold = r"\s+Threshold:\s+([-+\s]\d+\.\d) LUFS"
lufs_LRA = r"\s+LRA:\s+([-+\s]\d+\.\d) LU"
luss_LRS_low = r"\s+LRA low:\s+([-+\s]\d+\.\d) LUFS"
luss_LRS_high = r"\s+LRA high:\s+([-+\s]\d+\.\d) LUFS"
mean_volume = r"\[Parsed_volumedetect_0 @ \w+\] mean_volume:\s(-\d+\.\d) dB"
max_volume = r"\[Parsed_volumedetect_0 @ \w+\] max_volume:\s(-\d+\.\d) dB"
cmd_lufs = 'ffmpeg -nostats -i {0} -filter_complex ebur128 -f null -'
cmd_db = 'ffmpeg -i {0} -af "volumedetect" -f null -'
dict_loudnes = {}
output = subprocess.getstatusoutput(cmd_lufs.format(audiofile))
if output:
lines = output[1].splitlines()
end_match = 0
for i in range(len(lines)):
if 'TARGET:-23 LUFS' in lines[i]:
for j in range(i+1, len(lines)):
line = lines[j]
if 'I:' in line:
match = re.search(lufs_I, line)
if match:
dict_loudnes['I(LUFS)'] = match.group(1)
if 'Threshold:' in line:
match = re.search(lufs_Threshold, line)
if match:
dict_loudnes['Threshold(LUFS)'] = match.group(1)
if 'LRA:' in line:
match = re.search(lufs_LRA, line)
if match:
dict_loudnes['LRA(LU)'] = match.group(1)
if 'LRA low:' in line:
match = re.search(luss_LRS_low, line)
if match:
dict_loudnes['LRA_low(LUFS)'] = match.group(1)
if 'LRA high' in line:
match = re.search(luss_LRS_high, line)
if match:
dict_loudnes['LRA_high(LUFS)'] = match.group(1)
end_match = 1
break
if end_match:
break
output_db = subprocess.getstatusoutput(cmd_db.format(audiofile))
if output_db:
match = re.search(mean_volume, output_db[1])
if match:
dict_loudnes['mean_volume(dB)'] = match.group(1)
match = re.search(max_volume, output_db[1])
if match:
dict_loudnes['max_volume(dB)'] = match.group(1)
return dict_loudnes
'''
:param '/Users/yy/Documents/test_noise/agc/android_new'
:return write csv file
'''
def get_audio_loudness_by_path(file_path):
audio_loudness_list = []
file_path = os.path.abspath(file_path)
for file in os.listdir(file_path):
if file.endswith('.mp3') or file.endswith('wav'):
dict_loudnes = get_audio_loudness_by_file(os.path.join(file_path, file))
dict_loudnes['audio_name'] = file
audio_loudness_list.append(dict_loudnes)
print(audio_loudness_list)
csvname = os.path.join(file_path, os.path.basename(file_path) + '.csv')
print(csvname)
with open(csvname, 'w', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['audio_name', 'I(LUFS)', 'Threshold(LUFS)', 'LRA(LU)', 'LRA_low(LUFS)', 'LRA_high(LUFS)', 'mean_volume(dB)', 'max_volume(dB)'])
writer.writeheader()
writer.writerows(audio_loudness_list)
'''
:
:return 瞬时响度(由M标识)、短期响度(S)、综合响度(I)和响度范围(LRA)
[Parsed_ebur128_0 @ 0x7ff27302c900] t: 0.299979 TARGET:-23 LUFS M:-120.7 S:-120.7 I: -70.0 LUFS LRA: 0.0 LU
# 音频每100ms的瞬时响度(由M标识)、短期响度(S)、综合响度(I)和响度范围(LRA)
'''
def get_audio_detail_loudness_by_file(audio_file):
ebur = r'\[Parsed_ebur128_0 @ \w+\]\s+t:\s+(\d+[\.\d+]*)\s+TARGET:(-\d+)\sLUFS\s+M:([-\s]*\d+\.\d)\s+S:([-\s]*\d+\.\d)\s+I:\s+([-\s]*\d+\.\d)\sLUFS\s+LRA:\s+(\d+\.\d)\sLU'
cmd_lufs = 'ffmpeg -nostats -i {0} -filter_complex ebur128 -f null -'
cmd = cmd_lufs.format(audio_file)
# print(cmd)
detail_list = []
output = subprocess.getstatusoutput(cmd)
if output:
lines = output[1].splitlines()
for line in lines:
match = re.search(ebur, line)
dict_loudnes = {}
if match:
dict_loudnes['time'] = match.group(1)
dict_loudnes['TARGET(LUFS)'] = match.group(2)
dict_loudnes['M(LUFS)'] = match.group(3)
dict_loudnes['S(LUFS)'] = match.group(4)
dict_loudnes['I(LUFS)'] = match.group(5)
dict_loudnes['LRA(LU)'] = match.group(6)
detail_list.append(dict_loudnes)
if len(detail_list) > 1:
csvname = audio_file + '.csv'
print(csvname)
dict_loudness = get_audio_loudness_by_file(audio_file)
info_str = 'agv_I={1}{0} LRA_low={2}{0} LRA_high={3}{0}'.format('LUFS', dict_loudness['I(LUFS)'], dict_loudness['LRA_low(LUFS)'], dict_loudness['LRA_high(LUFS)'])
info = [info_str]
print(dict_loudness)
with open(csvname, 'w', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerow(info)
writer = csv.DictWriter(f, fieldnames=['time', 'TARGET(LUFS)', 'M(LUFS)', 'S(LUFS)', 'I(LUFS)',
'LRA(LU)'])
writer.writeheader()
writer.writerows(detail_list)
def get_audio_detail_loudness_by_path(file_path):
file_path = os.path.abspath(file_path)
for root, dirs, files in os.walk(file_path):
for file in files:
if file.endswith('.mp3') or file.endswith('wav'):
print(os.path.join(root, file))
get_audio_detail_loudness_by_file(os.path.join(root, file))
if __name__ == "__main__":
print('xx')
test_file = '/Users/yy/Documents/test_noise/agc/android_new/test_saopin_32bit.wav'
get_audio_detail_loudness_by_file(test_file)
if len(sys.argv) > 1:
temp = sys.argv[1]
if os.path.isdir(temp):
print('path', temp)
get_audio_loudness_by_path(temp)
get_audio_detail_loudness_by_path(temp)
elif os.path.isfile(temp):
print('file', temp)
get_audio_loudness_by_file(temp)
else:
print(temp, 'is not exists')
else:
print('param need path or file')