diff --git a/scripts/parse_mld.py b/scripts/parse_mld.py new file mode 100644 index 0000000000000000000000000000000000000000..2a60e176e366a3d3cfbc1f914928f36ede3386a5 --- /dev/null +++ b/scripts/parse_mld.py @@ -0,0 +1,29 @@ +#!/usr/bin/python3 + +import argparse +import re + + +# Main routine +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Parse HTML report to extract MLD values') + parser.add_argument('html_report',type=str,help='HTML report input file, e.g. report.html') + parser.add_argument('csv_file',type=str,help='Output CSV file, e.g. output.csv') + args = parser.parse_args() + html_report = args.html_report + csv_file = args.csv_file + + mld = {} + + with open(html_report,'r') as infile: + for line in infile.readlines(): + if "col-name" in line: + test_name = re.search('\[(.*)\]', line).group(1) + mld[test_name] = 0.0 + if "MLD" in line: + mld_val = float(line.split()[1]) + mld[test_name] = mld_val + + with open(csv_file,'w') as outfile: + for test_name in mld: + outfile.write(test_name + ';' + str(mld[test_name])+'\n') \ No newline at end of file diff --git a/scripts/pyaudio3dtools/audioarray.py b/scripts/pyaudio3dtools/audioarray.py index 740c40c3c6fda3cdc9f0112d3dfbfad9c6f5e1dc..280b7e9aa4485bb81cc85e87686479530806603d 100644 --- a/scripts/pyaudio3dtools/audioarray.py +++ b/scripts/pyaudio3dtools/audioarray.py @@ -37,6 +37,11 @@ from typing import Callable, Iterable, Optional, Tuple import numpy as np import multiprocessing as mp import scipy.signal as sig +import scipy.io.wavfile as wavfile +import subprocess +import platform +import tempfile +from pathlib import Path main_logger = logging.getLogger("__main__") logger = main_logger.getChild(__name__) @@ -221,7 +226,7 @@ def cut(x: np.ndarray, limits: Tuple[int, int]) -> np.ndarray: return y -def compare(ref: np.ndarray, test: np.ndarray, fs: int, per_frame: bool = True) -> dict: +def compare(ref: np.ndarray, test: np.ndarray, fs: int, per_frame: bool = True, get_mld: bool = False) -> dict: """Compare two audio arrays Parameters @@ -232,6 +237,10 @@ def compare(ref: np.ndarray, test: np.ndarray, fs: int, per_frame: bool = True) Input test array fs: int Input sampling rate in Hz + per_frame: bool + Compute difference per frame (default True) + get_mld: bool + Run MLD tool if there is a difference between the signals (default False) Returns ------- @@ -251,6 +260,7 @@ def compare(ref: np.ndarray, test: np.ndarray, fs: int, per_frame: bool = True) "first_diff_pos_sample": -1, "first_diff_pos_channel": -1, "first_diff_pos_frame": -1, + "MLD": 0 if get_mld else None, } if per_frame: result["max_abs_diff_pos_frame"] = 0 @@ -303,6 +313,30 @@ def compare(ref: np.ndarray, test: np.ndarray, fs: int, per_frame: bool = True) result["nframes_diff"] = nframes_diff result["nframes_diff_percentage"] = nframes_diff_percentage + if get_mld: + + mld_max = 0 + toolsdir = Path(__file__).parent.parent.joinpath("tools") + if platform.system() == "Windows": + mld = toolsdir.joinpath( "Win32").joinpath("mld.exe" ) + elif platform.system() in ["Linux", "Darwin"]: + mld = toolsdir.joinpath(platform.system()).joinpath( "mld" ) + else: + assert False, f"MLD tool not available for {platform.system()}" + + with tempfile.TemporaryDirectory() as tmpdir: + for i in range(nchannels): + tmpfile_ref = Path(tmpdir).joinpath(f"ref_ch{i+1}.wav") + tmpfile_test = Path(tmpdir).joinpath(f"test_ch{i+1}.wav") + r48 = resample(ref[:,i], fs, 48000); + t48 = resample(test[:,i], fs, 48000); + wavfile.write(str(tmpfile_ref), 48000, r48) + wavfile.write(str(tmpfile_test), 48000, t48) + out = subprocess.check_output([mld,tmpfile_ref,tmpfile_test]) + mld_max = max(mld_max, float(out.split()[3])) + + result["MLD"] = mld_max + return result diff --git a/scripts/tools/Linux/mld b/scripts/tools/Linux/mld new file mode 100644 index 0000000000000000000000000000000000000000..520d59be0ed27b998dc9eaf4ea4d56372e71293a Binary files /dev/null and b/scripts/tools/Linux/mld differ diff --git a/scripts/tools/Win32/mld.exe b/scripts/tools/Win32/mld.exe new file mode 100644 index 0000000000000000000000000000000000000000..88146ad69c8d85da63ad6c7c744bbf65e92e0fb2 --- /dev/null +++ b/scripts/tools/Win32/mld.exe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:586e9b5dbc9138f3c1c5b78a30edac85c848f5fb9cbf575b9fe08725fd647bef +size 198656 diff --git a/tests/cmp_pcm.py b/tests/cmp_pcm.py index a54aa2cf11fc56b6b5650adbe2b19855281f5227..817ac9c5026c249e8155353a9654bb2c659666cf 100755 --- a/tests/cmp_pcm.py +++ b/tests/cmp_pcm.py @@ -12,7 +12,7 @@ import pyivastest import numpy as np -def cmp_pcm(file1, file2, out_config, fs) -> (int, str): +def cmp_pcm(file1, file2, out_config, fs, get_mld = False) -> (int, str): """ Compare 2 PCM files for bitexactness """ @@ -34,6 +34,8 @@ def cmp_pcm(file1, file2, out_config, fs) -> (int, str): s1, _ = pyaudio3dtools.audiofile.readfile(file1, nchannels, fs, outdtype=np.int16) s2, _ = pyaudio3dtools.audiofile.readfile(file2, nchannels, fs, outdtype=np.int16) + nchannels = s1.shape[1] # In case of wav input, override the nchannels with the one from the wav header + if s1.shape != s2.shape: print( f"file size in samples: file 1 = {s1.shape[0]},", @@ -41,7 +43,7 @@ def cmp_pcm(file1, file2, out_config, fs) -> (int, str): ) return 1, "FAIL: File lengths differ" - cmp_result = pyaudio3dtools.audioarray.compare(s1, s2, fs, per_frame=False) + cmp_result = pyaudio3dtools.audioarray.compare(s1, s2, fs, per_frame=False, get_mld=get_mld) if cmp_result["bitexact"]: return 0, "SUCCESS: Files are bitexact" @@ -50,6 +52,9 @@ def cmp_pcm(file1, file2, out_config, fs) -> (int, str): first_msg = f"First diff found at sample num {cmp_result['first_diff_pos_sample']} in channel {cmp_result['first_diff_pos_channel']}, frame {cmp_result['first_diff_pos_frame']} (assuming {nchannels} channels, {fs} sampling rate)" print(diff_msg) print(first_msg) + if get_mld: + mld_msg = f"MLD: {cmp_result['MLD']}" + print(mld_msg) return 1, "FAIL: Files have different content" @@ -65,6 +70,7 @@ if __name__ == "__main__": choices=pyivastest.constants.OC_TO_NCHANNELS.keys(), ) parser.add_argument("-s", "--sampling_rate", type=int, default=48000, dest="fs") + parser.add_argument("--get_mld", action="store_true") args = parser.parse_args() result, msg = cmp_pcm(**vars(args)) diff --git a/tests/conftest.py b/tests/conftest.py index 46cd0d3a611b7b38dd0967991a1bf2210b8808f5..4b38ef776a4388059033cf2d579e5730e0fac3b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -152,6 +152,12 @@ def pytest_addoption(parser): help="Timeout in seconds for each individual testcase. Default is no timeout.", ) + parser.addoption( + "--mld", + action="store_true", + help="Run the MLD tool instead of just comparing for bitexactness", + ) + @pytest.fixture(scope="session", autouse=True) def update_ref(request): @@ -164,6 +170,14 @@ def update_ref(request): return int(request.config.getoption("--update_ref")) +@pytest.fixture(scope="session", autouse=True) +def get_mld(request): + """ + Return indication to run the MLD tool during ref/dut comparison. + """ + return request.config.option.mld + + @pytest.fixture(scope="session") def keep_files(request) -> bool: """