From e7e90bc604f4e7b1f8664f5d4d270d09b3ebc0a2 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Tue, 23 Sep 2025 16:49:34 +0200 Subject: [PATCH 1/7] add test for comparing flt and fx ambi_converter for BE --- .../test_be_ambi_converter_fixed_to_float.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 tests/test_be_ambi_converter_fixed_to_float.py diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py new file mode 100644 index 0000000000..238a9ed695 --- /dev/null +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -0,0 +1,99 @@ +import pytest +import subprocess +import sys +from enum import Enum +from pathlib import Path +from tempfile import TemporaryDirectory + +HERE = Path(__file__).absolute().parent +TESTV_DIR = HERE.parent / "scripts/testv" + +sys.path.append(str(HERE.parent / "scripts")) +from pyaudio3dtools import audiofile, audioarray + + +class AMBI_CONVENTION(int, Enum): + ACN_SN3D = 0 + ACN_N3D = 1 + FUMA_MAXN = 2 + FUMA_FUMA = 3 + SID_SN3D = 4 + SID_N3D = 5 + + +def run_ambi_converter( + bin_path: Path, + infile: Path, + outfile: str, + convention_in: AMBI_CONVENTION, + convention_out: AMBI_CONVENTION, +): + cmd = [ + str(bin_path), + str(infile), + outfile, + f"{int(convention_in)}", + f"{int(convention_out)}", + ] + + p = subprocess.run(cmd, capture_output=True) + if p.returncode != 0: + pytest.fail( + f"Ambisonics converter run failed: {p.stdout.decode('utf8') + p.stderr.decode('utf8')}" + ) + + +INPUT_FILES = [TESTV_DIR / "stv3OA48c.wav"] +CONVENTIONS = [c.value for c in AMBI_CONVENTION] +AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" +AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" + + +@pytest.mark.parametrize("infile", INPUT_FILES) +@pytest.mark.parametrize("convention_out", CONVENTIONS) +@pytest.mark.parametrize("convention_in", CONVENTIONS) +def test_ambi_converter( + infile: Path, + convention_in: AMBI_CONVENTION, + convention_out: AMBI_CONVENTION, + # needs to be passed to correctly report errors + test_info, +): + if ( + convention_out != AMBI_CONVENTION.ACN_SN3D + and convention_in != AMBI_CONVENTION.ACN_SN3D + ): + pytest.skip("One of in and out convention needs to be ACN_SN3D") + + with TemporaryDirectory() as tmp_dir: + outfile_base = Path(tmp_dir) / ( + infile.stem + f"-{str(convention_in)}-to-{str(convention_out)}" + ) + + outfile_flt = str(outfile_base) + "-flt.wav" + outfile_fx = str(outfile_base) + "-fx.wav" + + run_ambi_converter( + AMBI_CONVERTER_PATH_FLOAT, + infile, + outfile_flt, + convention_in, + convention_out, + ) + + run_ambi_converter( + AMBI_CONVERTER_PATH_FIXED, + infile, + outfile_fx, + convention_in, + convention_out, + ) + + s_flt, _ = audiofile.readfile(outfile_flt) + s_fx, _ = audiofile.readfile(outfile_fx) + + cmp_result = audioarray.compare(s_flt, s_fx, fs=48000, per_frame=False) + if not cmp_result["bitexact"]: + pytest.fail( + f"Difference between float and fixed ambi_converter output found! Max abs diff: {cmp_result['max_abs_diff']}" + ) -- GitLab From 3b669c894593b720d80ef4aaeb90a8951093d7f4 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Wed, 24 Sep 2025 08:58:15 +0200 Subject: [PATCH 2/7] introduce dummy threshold and use xfail instead of skip --- tests/test_be_ambi_converter_fixed_to_float.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 238a9ed695..0ff1499809 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -47,6 +47,7 @@ INPUT_FILES = [TESTV_DIR / "stv3OA48c.wav"] CONVENTIONS = [c.value for c in AMBI_CONVENTION] AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" +THRESHOLD_FAIL = 2 @pytest.mark.parametrize("infile", INPUT_FILES) @@ -63,7 +64,7 @@ def test_ambi_converter( convention_out != AMBI_CONVENTION.ACN_SN3D and convention_in != AMBI_CONVENTION.ACN_SN3D ): - pytest.skip("One of in and out convention needs to be ACN_SN3D") + pytest.xfail("One of in and out convention needs to be ACN_SN3D") with TemporaryDirectory() as tmp_dir: outfile_base = Path(tmp_dir) / ( @@ -93,7 +94,7 @@ def test_ambi_converter( s_fx, _ = audiofile.readfile(outfile_fx) cmp_result = audioarray.compare(s_flt, s_fx, fs=48000, per_frame=False) - if not cmp_result["bitexact"]: + if abs(cmp_result["max_abs_diff"]) > THRESHOLD_FAIL: pytest.fail( f"Difference between float and fixed ambi_converter output found! Max abs diff: {cmp_result['max_abs_diff']}" ) -- GitLab From 22938cb097426f2170ac974ae4cc0bafc215d502 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Wed, 24 Sep 2025 14:07:08 +0200 Subject: [PATCH 3/7] implement keep_files arg and add printout of command --- tests/test_be_ambi_converter_fixed_to_float.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 0ff1499809..264b5565de 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -7,6 +7,7 @@ from tempfile import TemporaryDirectory HERE = Path(__file__).absolute().parent TESTV_DIR = HERE.parent / "scripts/testv" +OUTPUT_FOLDER_IF_KEEP_FILES = HERE.joinpath("output-ambi_converter-be") sys.path.append(str(HERE.parent / "scripts")) from pyaudio3dtools import audiofile, audioarray @@ -35,12 +36,12 @@ def run_ambi_converter( f"{int(convention_in)}", f"{int(convention_out)}", ] + print(" ".join(cmd)) p = subprocess.run(cmd, capture_output=True) if p.returncode != 0: - pytest.fail( - f"Ambisonics converter run failed: {p.stdout.decode('utf8') + p.stderr.decode('utf8')}" - ) + msg = f"{p.stdout.decode('utf8')}\n{p.stderr.decode('utf8')}" + pytest.fail(f"Ambisonics converter run failed:\n{msg}") INPUT_FILES = [TESTV_DIR / "stv3OA48c.wav"] @@ -57,6 +58,7 @@ def test_ambi_converter( infile: Path, convention_in: AMBI_CONVENTION, convention_out: AMBI_CONVENTION, + keep_files, # needs to be passed to correctly report errors test_info, ): @@ -66,8 +68,13 @@ def test_ambi_converter( ): pytest.xfail("One of in and out convention needs to be ACN_SN3D") + if keep_files: + OUTPUT_FOLDER_IF_KEEP_FILES.mkdir(exist_ok=True, parents=True) + with TemporaryDirectory() as tmp_dir: - outfile_base = Path(tmp_dir) / ( + output_dir = OUTPUT_FOLDER_IF_KEEP_FILES if keep_files else tmp_dir + + outfile_base = Path(output_dir) / ( infile.stem + f"-{str(convention_in)}-to-{str(convention_out)}" ) -- GitLab From fa7a741a9e65585dada56e38062f162d69cc6cac Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Wed, 24 Sep 2025 14:41:04 +0200 Subject: [PATCH 4/7] improve testcase naming --- .../test_be_ambi_converter_fixed_to_float.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 264b5565de..265fd643b8 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -1,5 +1,6 @@ import pytest import subprocess +import itertools import sys from enum import Enum from pathlib import Path @@ -45,15 +46,26 @@ def run_ambi_converter( INPUT_FILES = [TESTV_DIR / "stv3OA48c.wav"] -CONVENTIONS = [c.value for c in AMBI_CONVENTION] +CONVENTIONS = [c for c in AMBI_CONVENTION] AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" THRESHOLD_FAIL = 2 - -@pytest.mark.parametrize("infile", INPUT_FILES) -@pytest.mark.parametrize("convention_out", CONVENTIONS) -@pytest.mark.parametrize("convention_in", CONVENTIONS) +CONVENTIONS_FULL_COMBI = list(itertools.product(CONVENTIONS, CONVENTIONS)) +CONVENTIONS_TEST_PARAMS = [ + (c_in.value, c_out.value) for c_in, c_out in CONVENTIONS_FULL_COMBI +] +CONVENTIONS_TEST_PARAMS_IDS = [ + f"{c_in.name}-to-{c_out.name}" for c_in, c_out in CONVENTIONS_FULL_COMBI +] + + +@pytest.mark.parametrize("infile", INPUT_FILES, ids=[p.name for p in INPUT_FILES]) +@pytest.mark.parametrize( + "convention_in,convention_out", + CONVENTIONS_TEST_PARAMS, + ids=CONVENTIONS_TEST_PARAMS_IDS, +) def test_ambi_converter( infile: Path, convention_in: AMBI_CONVENTION, -- GitLab From 476debe59d8b8e336a2a7b8de40710ae1b85b0d5 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Wed, 24 Sep 2025 15:31:06 +0200 Subject: [PATCH 5/7] switch to other input files for ambi_converter test - use the spectral_test items now --- tests/test_be_ambi_converter_fixed_to_float.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 265fd643b8..8fdd81e3cc 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -45,7 +45,9 @@ def run_ambi_converter( pytest.fail(f"Ambisonics converter run failed:\n{msg}") -INPUT_FILES = [TESTV_DIR / "stv3OA48c.wav"] +# test all ambisonics orders from 1 to 3 +INPUT_CH_NUM = [4, 9, 16] +INPUT_FILES = [TESTV_DIR / f"spectral_test_{ch}ch_48kHz.wav" for ch in INPUT_CH_NUM] CONVENTIONS = [c for c in AMBI_CONVENTION] AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" -- GitLab From bbecfe429b1d1069a94899dbbd702647019af0f8 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Mon, 6 Oct 2025 11:02:21 +0200 Subject: [PATCH 6/7] change error tolerance to +/- 1LSB max --- tests/test_be_ambi_converter_fixed_to_float.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 8fdd81e3cc..0d0b1f1ade 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -51,7 +51,7 @@ INPUT_FILES = [TESTV_DIR / f"spectral_test_{ch}ch_48kHz.wav" for ch in INPUT_CH_ CONVENTIONS = [c for c in AMBI_CONVENTION] AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" -THRESHOLD_FAIL = 2 +THRESHOLD_FAIL = 1 CONVENTIONS_FULL_COMBI = list(itertools.product(CONVENTIONS, CONVENTIONS)) CONVENTIONS_TEST_PARAMS = [ -- GitLab From 2d92741efbef349f62ccbd315b6361d99b1f9403 Mon Sep 17 00:00:00 2001 From: Jan Kiene Date: Mon, 6 Oct 2025 11:09:29 +0200 Subject: [PATCH 7/7] add other sampling rates --- tests/test_be_ambi_converter_fixed_to_float.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_be_ambi_converter_fixed_to_float.py b/tests/test_be_ambi_converter_fixed_to_float.py index 0d0b1f1ade..aa4202d3d1 100644 --- a/tests/test_be_ambi_converter_fixed_to_float.py +++ b/tests/test_be_ambi_converter_fixed_to_float.py @@ -47,7 +47,12 @@ def run_ambi_converter( # test all ambisonics orders from 1 to 3 INPUT_CH_NUM = [4, 9, 16] -INPUT_FILES = [TESTV_DIR / f"spectral_test_{ch}ch_48kHz.wav" for ch in INPUT_CH_NUM] +INPUT_FS = [16, 32, 48] +INPUT_FILES = [ + TESTV_DIR / f"spectral_test_{ch}ch_{fs}kHz.wav" + for ch in INPUT_CH_NUM + for fs in INPUT_FS +] CONVENTIONS = [c for c in AMBI_CONVENTION] AMBI_CONVERTER_PATH_FLOAT = HERE.parent / "ambi_converter_flt" AMBI_CONVERTER_PATH_FIXED = HERE.parent / "ambi_converter_fx" -- GitLab