diff --git a/scripts/batch_comp_audio.py b/scripts/batch_comp_audio.py index 97e9f8f54840f22f71fddb44ebd0bddd8fa486ce..ef47968cb83d33693d9d3e3d87c2deda505536ed 100755 --- a/scripts/batch_comp_audio.py +++ b/scripts/batch_comp_audio.py @@ -33,40 +33,52 @@ import argparse import concurrent.futures import os +import pathlib import re import shutil import subprocess import sys import threading from itertools import repeat +from pyaudio3dtools.audiofile import readfile +from pyaudio3dtools.audioarray import compare FILES_EQUAL = "File A = File B" -SNR_EXPR = r"SNR\s+=(.+)dB\s*\(File B Gain = (.+)\)" +SNR_EXPR = r"SNR\s+=(.+)dB\s*\(.+= (.+)\)" SEG_SNR_EXPR = r"Seg. SNR\s+=(.+)dB" DIFF_EXPR = r"Max Diff\s+=\s+(\d+)" +DIFF_STR = { + "CompAudio": "{label} Max. diff (PCM) for file {f}: {diff}", + "mld": "{label} MLD diff for file {f}: {diff}", +} def main(args): - - if shutil.which("CompAudio") is None: - print("CompAudio not in PATH - abort.") + tool = args.tool + if shutil.which(tool) is None: + print(f"{tool} not in PATH - abort.") sys.exit(-1) num_files_diff = 0 with OutFileManager(args.out_file) as out_file: if args.diffs_only: - print("Only printing differing files!", file=out_file) + print("Only printing differing files!") fol1, fol2 = os.path.normpath(args.folder1), os.path.normpath(args.folder2) common_files = get_common_files(fol1, fol2) diff_files = get_diff_files(fol1, fol2) num_files_diff = len(diff_files) - print(f"Comparing {len(common_files)} files...", file=out_file) + print(f"Comparing {len(common_files)} files...") outputs = dict() - if args.num_threads > 1: + if args.num_threads == 1: + # if only one thread is passed, do everything in the main thread + # to allow for meaningful debugging if needed + for f in common_files: + compare_files(f, fol1, fol2, outputs, tool) + else: with concurrent.futures.ThreadPoolExecutor( max_workers=args.num_threads ) as exc: @@ -76,20 +88,26 @@ def main(args): repeat(fol1), repeat(fol2), repeat(outputs), + repeat(tool), ) - else: - # if only one thread is passed, do everything in the main thread - # to allow for meaningful debugging if needed - for f in common_files: - compare_files(f, fol1, fol2, outputs) if args.sort: out = dict(sorted(outputs.items(), key=lambda item: item[1])) else: out = outputs - for f, output_tuple in out.items(): - diff, snr, gain, seg_snr = output_tuple + # write csv header + if out_file is not None: + if tool == "CompAudio": + out_file.write("filename,diff\n") + elif tool == "mld": + out_file.write("filename,mld\n") + + for f, tool_output in out.items(): + if tool == "CompAudio": + diff, snr, gain, seg_snr = tool_output + elif tool == "mld": + diff = tool_output if diff > 0: num_files_diff = num_files_diff + 1 @@ -99,38 +117,47 @@ def main(args): label = "[OKAY]" else: label = "[FAIL]" - result = f"{label} Max. diff (PCM) for file {f}: {diff}" + result = DIFF_STR[tool].format(label=label, f=f, diff=diff) - if args.verbose and diff != 0.0: + if tool == "CompAudio" and args.verbose and diff != 0.0: result += f", SNR = {snr:4.2f} dB (File 2 Gain = {gain:4.3f})" result += f", Seg. SNR = {seg_snr:4.2f} dB" - print(result, file=out_file) + print(result) + + if out_file is not None: + out_file.write(f"{f},{diff}\n") if num_files_diff > 0: - print(f"{num_files_diff} files differ/don't exist", file=out_file) + print(f"{num_files_diff} files differ/don't exist") else: - print(f"All files are bitexact", file=out_file) + print(f"All files are bitexact") -def compare_files(f, fol1, fol2, outputs_dict): +def compare_files(f, fol1, fol2, outputs_dict, tool): """ - Compare file f in both folders fol1 and fol2 using CompAudio and + Compare file f in both folders fol1 and fol2 using the given tool and store the parsed difference in outputs_dict. """ f1 = os.path.join(fol1, f) f2 = os.path.join(fol2, f) - cmd = f"CompAudio {f1} {f2}" - try: - output = subprocess.check_output(cmd.split(" ")) - except subprocess.CalledProcessError: - print("CompAudio returned a non-zero exit status. Check your files.") - sys.exit(-1) - output_tuple = _parse_comp_audio(output) + if tool == "CompAudio": + cmd = f"{tool} {f1} {f2}" + try: + output = subprocess.check_output(cmd.split(" ")) + except subprocess.CalledProcessError: + print(f"{tool} returned a non-zero exit status. Check your files.") + sys.exit(-1) + tool_output = _parse_comp_audio(output) + elif tool == "mld": + s1, fs1 = readfile(f1, outdtype="int16") + s2, fs2 = readfile(f2, outdtype="int16") + cmp_result = compare(s1, s2, fs1, per_frame=False, get_mld=True) + tool_output = cmp_result["MLD"] with threading.Lock(): - outputs_dict.update({f: output_tuple}) + outputs_dict.update({f: tool_output}) def get_common_files(fol1, fol2): @@ -220,7 +247,6 @@ class OutFileManager: if __name__ == "__main__": - parser = argparse.ArgumentParser( description="Compare .wav files in two folders using CompAudio" ) @@ -251,10 +277,16 @@ if __name__ == "__main__": "--out_file", type=str, default=None, - help="If given, write output diffs to this file", + help="If given, write output diffs to this file as comma-separated values (csv)", + ) + parser.add_argument( + "-t", "--num_threads", type=int, default=None, help="Number of threads to use" ) parser.add_argument( - "-t", "--num_threads", type=int, default=1, help="Number of threads to use" + "--tool", + choices=["mld", "CompAudio"], + default="CompAudio", + help="Compare tool to run", ) args = parser.parse_args()