diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7347178cbb25f9b812d9a72f765138cd66a6b733..2dfef304e383e6470567807613f3cf6adba64fd6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,11 +67,13 @@ format: script: - mkdir $ARTIFACT_FOLDER - - isort --profile black . || ret_val_isort=$? - - black . || ret_val_black=$? - - git diff > "${ARTIFACT_FOLDER}/${ARTIFACT_BASE_NAME}.patch" + - isort --profile black . + - black . - - if [[ $ret_val_isort != 0 || $ret_val_black != 0 ]]; then exit 1; fi + - patch_file="${ARTIFACT_FOLDER}/${ARTIFACT_BASE_NAME}.patch" + - git diff > $patch_file + + - if [ -s $patch_file ]; then exit 1; fi artifacts: paths: - "$ARTIFACT_FOLDER" diff --git a/ivas_processing_scripts/audiotools/audioarray.py b/ivas_processing_scripts/audiotools/audioarray.py index 2f921b3fa9da945d9f4a771fc23b3c9c2389a830..5b2c60e4f4c71487f0cf3dc14d41dcd8a5ae7043 100755 --- a/ivas_processing_scripts/audiotools/audioarray.py +++ b/ivas_processing_scripts/audiotools/audioarray.py @@ -42,7 +42,7 @@ logger = logging.getLogger("__main__") logger.setLevel(logging.DEBUG) -### Functions used in this module +# Functions used in this module def trim( x: np.ndarray, fs: Optional[int] = 48000, @@ -183,13 +183,13 @@ def delay_compensation( """ # Get the delay in number of samples - if flt_type == "SHQ2" and up == True: + if flt_type == "SHQ2" and up: d_samples = DELAY_COMPENSATION_FOR_FILTERING["SHQ2"]["up"] - elif flt_type == "SHQ2" and down == True: + elif flt_type == "SHQ2" and down: d_samples = DELAY_COMPENSATION_FOR_FILTERING["SHQ2"]["down"] - elif flt_type == "SHQ3" and up == True: + elif flt_type == "SHQ3" and up: d_samples = DELAY_COMPENSATION_FOR_FILTERING["SHQ3"]["up"] - elif flt_type == "SHQ3" and down == True: + elif flt_type == "SHQ3" and down: d_samples = DELAY_COMPENSATION_FOR_FILTERING["SHQ3"]["down"] else: d_samples = DELAY_COMPENSATION_FOR_FILTERING[flt_type] @@ -405,7 +405,7 @@ def framewise_io( ) -### Deprecated functions (partly replaced by ITU binaries) +# Deprecated functions (partly replaced by ITU binaries) def resample( x: np.ndarray, in_freq: int, diff --git a/ivas_processing_scripts/audiotools/binaural_datasets/binaural_dataset.py b/ivas_processing_scripts/audiotools/binaural_datasets/binaural_dataset.py index 7062dfb3c45d04409ea9cdfc3440e787f7a3b08e..ab86d66a5c4de13ca9aeaaa9a24890fa45ec1bcd 100755 --- a/ivas_processing_scripts/audiotools/binaural_datasets/binaural_dataset.py +++ b/ivas_processing_scripts/audiotools/binaural_datasets/binaural_dataset.py @@ -30,7 +30,6 @@ # the United Nations Convention on Contracts on the International Sales of Goods. # -import logging import warnings from pathlib import Path from typing import Optional, Tuple, Union @@ -142,15 +141,23 @@ def load_ir( if in_fmt == "SBA1" or in_fmt == "FOA": dataset_suffix = "SBA1" # Use truncated SBA3 dataset if no SBA1 or 2 dataset exists - if not (Path(__file__).parent.joinpath(f"{dataset_prefix}_{dataset}_{dataset_suffix}.mat")).is_file(): + if not ( + Path(__file__).parent.joinpath( + f"{dataset_prefix}_{dataset}_{dataset_suffix}.mat" + ) + ).is_file(): dataset_suffix = "SBA3" - warnings.warn(f"No SBA1 dataset found -> use truncated SBA3 dataset") + warnings.warn("No SBA1 dataset found -> use truncated SBA3 dataset") elif in_fmt.endswith("2"): dataset_suffix = "SBA2" # Use truncated SBA3 dataset if no SBA1 or 2 dataset exists - if not (Path(__file__).parent.joinpath(f"{dataset_prefix}_{dataset}_{dataset_suffix}.mat")).is_file(): + if not ( + Path(__file__).parent.joinpath( + f"{dataset_prefix}_{dataset}_{dataset_suffix}.mat" + ) + ).is_file(): dataset_suffix = "SBA3" - warnings.warn(f"No SBA2 dataset found -> use truncated SBA3 dataset") + warnings.warn("No SBA2 dataset found -> use truncated SBA3 dataset") else: dataset_suffix = "SBA3" diff --git a/ivas_processing_scripts/audiotools/convert/__init__.py b/ivas_processing_scripts/audiotools/convert/__init__.py index 9b09cf8f9ec660809fad1102a5fff5225b73cca1..d92c2b3a24f6a4e284bd997dbf6f3b09603215cc 100755 --- a/ivas_processing_scripts/audiotools/convert/__init__.py +++ b/ivas_processing_scripts/audiotools/convert/__init__.py @@ -41,12 +41,12 @@ from ivas_processing_scripts.audiotools.convert.masa import convert_masa from ivas_processing_scripts.audiotools.convert.objectbased import convert_objectbased from ivas_processing_scripts.audiotools.convert.scenebased import convert_scenebased from ivas_processing_scripts.audiotools.wrappers.bs1770 import loudness_norm +from ivas_processing_scripts.audiotools.wrappers.esdru import esdru from ivas_processing_scripts.audiotools.wrappers.filter import ( hp50filter_itu, lpfilter_itu, resample_itu, ) -from ivas_processing_scripts.audiotools.wrappers.esdru import esdru from ivas_processing_scripts.audiotools.wrappers.p50fbmnru import p50fbmnru from ..metadata import write_ISM_metadata_in_file @@ -258,13 +258,13 @@ def process_audio( """MNRU""" if mnru_q is not None: if logger: - logger.debug(f"Applying P.50 Fullband MNRU") + logger.debug("Applying P.50 Fullband MNRU") x.audio = p50fbmnru(x, mnru_q) """ESDRU""" if esdru_alpha is not None: if logger: - logger.debug(f"Applying ESDRU Recommendation ITU-T P.811") + logger.debug("Applying ESDRU Recommendation ITU-T P.811") x.audio = esdru(x, esdru_alpha) """limiting""" @@ -284,17 +284,19 @@ def format_conversion( # validation if isinstance(output, audio.MetadataAssistedSpatialAudio): - raise NotImplementedError(f"MASA is not supported as an output for rendering!") + raise NotImplementedError("MASA is not supported as an output for rendering!") if isinstance(output, audio.ObjectBasedAudio) and input.name != output.name: raise NotImplementedError( - f"ISM is not supported as an output for rendering! Only usable as pass-through" + "ISM is not supported as an output for rendering! Only usable as pass-through" ) if logger: logger.debug(f"Format conversion: {input.name} -> {output.name}") - if input.name == output.name or (input.name.startswith("BINAURAL") and output.name.startswith("BINAURAL")): + if input.name == output.name or ( + input.name.startswith("BINAURAL") and output.name.startswith("BINAURAL") + ): output.audio = input.audio else: if isinstance(input, audio.BinauralAudio): diff --git a/ivas_processing_scripts/audiotools/convert/channelbased.py b/ivas_processing_scripts/audiotools/convert/channelbased.py index b0fadf99bb5b3c128e38343a9b18e34ea93873df..6540074c2bbf7b0baf0a6a9a58aceecca356deae 100755 --- a/ivas_processing_scripts/audiotools/convert/channelbased.py +++ b/ivas_processing_scripts/audiotools/convert/channelbased.py @@ -208,7 +208,6 @@ def render_cba_to_binaural( def render_cba_to_cba( cba_in: audio.ChannelBasedAudio, cba_out: audio.ChannelBasedAudio ) -> None: - # Stereo to Mono if cba_in.name == "STEREO" and cba_out.name == "MONO": render_mtx = np.vstack([[0.5], [0.5]]) @@ -244,7 +243,6 @@ def render_cba_to_cba( def render_cba_to_sba(cba: audio.ChannelBasedAudio, sba: audio.SceneBasedAudio) -> None: - if cba.name == "MONO": raise ValueError(f"Rendering from MONO to {sba.name} is not supported.") diff --git a/ivas_processing_scripts/audiotools/metadata.py b/ivas_processing_scripts/audiotools/metadata.py index a3f41bac775c9ce7e9a49afa77c3013af4e47f95..045d38d88553a634c1b83995b81affa8d7a123c3 100755 --- a/ivas_processing_scripts/audiotools/metadata.py +++ b/ivas_processing_scripts/audiotools/metadata.py @@ -412,7 +412,12 @@ def split_meta_in_file( # remove preamble if preamble: preamble_frames = int(preamble / IVAS_FRAME_LEN_MS) - y = trim(audio_object.object_pos[obj], audio_object.fs, (preamble_frames, 0), samples=True) + y = trim( + audio_object.object_pos[obj], + audio_object.fs, + (preamble_frames, 0), + samples=True, + ) else: y = audio_object.object_pos[obj] @@ -445,7 +450,7 @@ def check_ISM_metadata( path_meta = in_meta["all_items"] except KeyError: raise ValueError( - f'Only one metadata path is given but not with key "all_items".' + 'Only one metadata path is given but not with key "all_items".' ) list_meta = metadata_search(path_meta, item_names, num_objects) @@ -472,7 +477,7 @@ def check_ISM_metadata( # just read out list_item = current_item else: - raise ValueError(f"Number of objects and metadata does not match.") + raise ValueError("Number of objects and metadata does not match.") list_meta.append(list_item) else: raise ValueError("Number of metadata inputs does not match number of items") @@ -489,7 +494,7 @@ def metadata_search( """Search for ISM metadata with structure item_name.{0-3}.csv in in_meta folder""" if not item_names: - raise ValueError(f"Item names not provided, can't search for metadata") + raise ValueError("Item names not provided, can't search for metadata") list_meta = [] for item in item_names: diff --git a/ivas_processing_scripts/audiotools/wrappers/esdru.py b/ivas_processing_scripts/audiotools/wrappers/esdru.py index 7575796197fd375c7b59cbe5b8b3667ad6c6912f..a26ff511f379b493b0288cad156c56dc6556eac9 100755 --- a/ivas_processing_scripts/audiotools/wrappers/esdru.py +++ b/ivas_processing_scripts/audiotools/wrappers/esdru.py @@ -115,7 +115,7 @@ def esdru( write(tmp_output_file, tmp_output_signal, sf) # run command - result = run(cmd) + run(cmd) tmp_output_signal, out_fs = read(tmp_output_file, 2, sf) diff --git a/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py b/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py index a6b80187b456d816dc3c6a64b5a25dc0e43e05da..0c67b679c54e12a3d20826200eba1e99672422de 100755 --- a/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py +++ b/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py @@ -32,7 +32,7 @@ from pathlib import Path from tempfile import TemporaryDirectory -from typing import Optional, Tuple +from typing import Tuple from warnings import warn import numpy as np @@ -97,7 +97,7 @@ def p50fbmnru( write(tmp_output_file, tmp_output_signal) # run command - result = run(cmd) + run(cmd) tmp_output_signal, out_fs = read(tmp_output_file, input.num_channels) diff --git a/ivas_processing_scripts/constants.py b/ivas_processing_scripts/constants.py index 3c5184947e296c36181e7095b2004efc4ae6dee8..ff56b9bf29e07358b4a7b52f335882784e174e7c 100755 --- a/ivas_processing_scripts/constants.py +++ b/ivas_processing_scripts/constants.py @@ -40,7 +40,16 @@ LOGGER_FORMAT = ( ) LOGGER_DATEFMT = "%m-%d %H:%M:%S" -SUPPORTED_CONDITIONS = {"ref", "lp3k5", "lp7k", "mnru", "esdru", "evs", "ivas", "mono_dmx"} +SUPPORTED_CONDITIONS = { + "ref", + "lp3k5", + "lp7k", + "mnru", + "esdru", + "evs", + "ivas", + "mono_dmx", +} DEFAULT_CONFIG = { # general options diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index e495f5319e469b92370b1718b11dc0c3e3edf53a..1761cbbdeb02156ecc7ff3e356f57fcca14a391b 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -181,7 +181,8 @@ def get_processing_chain( "mnru_q": tmp_mnru_q, "esdru_alpha": tmp_esdru_alpha, } - )) + ) + ) tmp_in_fmt = "MONO" # add another postprocessing from in_fmt to mono elif cond_cfg["type"] == "evs": @@ -210,7 +211,7 @@ def get_processing_chain( cod_cfg = cond_cfg["cod"] dec_cfg = cond_cfg["dec"] - ### local tx overrides global one, or just allow global? + # local tx overrides global one, or just allow global? if "tx" in cond_cfg.keys(): tx_cfg = cond_cfg["tx"] elif hasattr(cfg, "tx"): diff --git a/ivas_processing_scripts/processing/config.py b/ivas_processing_scripts/processing/config.py index a6a943bdbb0906cdf39731e72f3b72452a29a350..b281e2a35135223ecbc1ee6ce08abac20d4273b3 100755 --- a/ivas_processing_scripts/processing/config.py +++ b/ivas_processing_scripts/processing/config.py @@ -40,10 +40,10 @@ from ivas_processing_scripts.constants import ( DEFAULT_CONFIG_EVS, DEFAULT_CONFIG_IVAS, REQUIRED_KEYS, + REQUIRED_KEYS_ESDRU, REQUIRED_KEYS_EVS, REQUIRED_KEYS_IVAS, REQUIRED_KEYS_MNRU, - REQUIRED_KEYS_ESDRU, SUPPORTED_CONDITIONS, ) @@ -174,7 +174,7 @@ class TestConfig: ) elif type == "esdru": if REQUIRED_KEYS_ESDRU.difference( - cfg["conditions_to_generate"][cond_name].keys() + cfg["conditions_to_generate"][cond_name].keys() ): raise KeyError( f"The following key must be specified for ESDRU: {REQUIRED_KEYS_ESDRU}" diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 0e9c3e441e2c48de9769caf6dcfc197014031a75..98cb5ce84abb421f05bbfcca03776afb9649ae07 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -31,11 +31,11 @@ # import logging +import platform from itertools import repeat from pathlib import Path from shutil import copyfile from typing import Optional -import platform from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import ( @@ -58,14 +58,18 @@ class EVS(Processing): self, ): if not self.cod_bin or not Path(self.cod_bin).exists(): - if platform.system() == "Windows" and (self.cod_bin and Path(self.cod_bin).with_suffix(".exe").exists()): + if platform.system() == "Windows" and ( + self.cod_bin and Path(self.cod_bin).with_suffix(".exe").exists() + ): self.cod_bin = Path(self.cod_bin).with_suffix(".exe") else: raise FileNotFoundError( "The EVS encoder binary was not found! Please check the configuration." ) if not self.dec_bin or not Path(self.dec_bin).exists(): - if platform.system() == "Windows" and (self.dec_bin and Path(self.dec_bin).with_suffix(".exe").exists()): + if platform.system() == "Windows" and ( + self.dec_bin and Path(self.dec_bin).with_suffix(".exe").exists() + ): self.dec_bin = Path(self.dec_bin).with_suffix(".exe") else: raise FileNotFoundError( diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index 18199f9be59f4e47422d4d34bf4a706ce6d76143..d7709360d50e01cbcc2c12b5449dea24e8dcbd03 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -32,10 +32,10 @@ import logging import os.path +import platform from copy import deepcopy from pathlib import Path from typing import Optional -import platform from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import parse_wave_header @@ -53,14 +53,18 @@ class IVAS(Processing): def _validate(self): if not self.cod_bin or not Path(self.cod_bin).exists(): - if platform.system() == "Windows" and (self.cod_bin and Path(self.cod_bin).with_suffix(".exe").exists()): + if platform.system() == "Windows" and ( + self.cod_bin and Path(self.cod_bin).with_suffix(".exe").exists() + ): self.cod_bin = Path(self.cod_bin).with_suffix(".exe") else: raise FileNotFoundError( "The IVAS encoder binary was not found! Please check the configuration." ) if not self.dec_bin or not Path(self.dec_bin).exists(): - if platform.system() == "Windows" and (self.dec_bin and Path(self.dec_bin).with_suffix(".exe").exists()): + if platform.system() == "Windows" and ( + self.dec_bin and Path(self.dec_bin).with_suffix(".exe").exists() + ): self.dec_bin = Path(self.dec_bin).with_suffix(".exe") else: raise FileNotFoundError( diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 30fb3068603dfc3e71adb3a61d989d2a324bcb1e..411f32790ccec7f379d1b97c3a9733d2ddf2976e 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -137,16 +137,16 @@ def concat_teardown(cfg: TestConfig, logger: logging.Logger): output_format = cfg.postprocessing["fmt"] if num_splits <= 1: - logger.info( - f"No splitting of output file necessary since only one signal used." - ) + logger.info("No splitting of output file necessary since only one signal used.") else: logger.info(f"Splitting output file in directory {cfg.output_path}") for odir in cfg.out_dirs: path_input = odir / cfg.items_list[0].name - out_paths = split(path_input, odir, cfg.split_names, cfg.splits, preamble=cfg.preamble) + out_paths = split( + path_input, odir, cfg.split_names, cfg.splits, preamble=cfg.preamble + ) logger.debug( f"Resulting split files condition {odir.name}: {', '.join([str(op) for op in out_paths])}" @@ -157,7 +157,12 @@ def concat_teardown(cfg: TestConfig, logger: logging.Logger): for odir in cfg.out_dirs: path_input = odir / cfg.items_list[0].name split_meta_in_file( - path_input, odir, cfg.split_names, cfg.splits, output_format, preamble=cfg.preamble + path_input, + odir, + cfg.split_names, + cfg.splits, + output_format, + preamble=cfg.preamble, ) # remove concatenated file diff --git a/tests/__init__.py b/tests/__init__.py index b3f5091dd62bebb89a56c5a28fc723142cfe61c0..8d3f6b8812b88c865663852cbcaf68a8df4ef8f2 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -25,14 +25,3 @@ # submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in # accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and # the United Nations Convention on Contracts on the International Sales of Goods. -# - -import pytest -from pathlib import Path -from .constants import OUTPUT_PATH_REF, OUTPUT_PATH_CUT - - -@pytest.fixture(scope="session", autouse=True) -def setup_test_environment(): - Path(OUTPUT_PATH_REF).mkdir(exist_ok=True) - Path(OUTPUT_PATH_CUT).mkdir(exist_ok=True) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..7b13574396a9ca7bf4929b51307ec22cc01cc50e --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,39 @@ +# (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository. All Rights Reserved. +# +# This software is protected by copyright law and by international treaties. +# The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, +# Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., +# Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, +# Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other +# contributors to this repository retain full ownership rights in their respective contributions in +# the software. This notice grants no license of any kind, including but not limited to patent +# license, nor is any license granted by implication, estoppel or otherwise. +# +# Contributors are required to enter into the IVAS codec Public Collaboration agreement before making +# contributions. +# +# This software is provided "AS IS", without any express or implied warranties. The software is in the +# development stage. It is intended exclusively for experts who have experience with such software and +# solely for the purpose of inspection. All implied warranties of non-infringement, merchantability +# and fitness for a particular purpose are hereby disclaimed and excluded. +# +# Any dispute, controversy or claim arising under or in relation to providing this software shall be +# submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in +# accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and +# the United Nations Convention on Contracts on the International Sales of Goods. + +from pathlib import Path + +import pytest + +from .constants import OUTPUT_PATH_CUT, OUTPUT_PATH_REF + + +@pytest.fixture(scope="session", autouse=True) +def setup_test_environment(): + Path(OUTPUT_PATH_REF).mkdir(exist_ok=True) + Path(OUTPUT_PATH_CUT).mkdir(exist_ok=True) diff --git a/tests/test_audiotools_convert.py b/tests/test_audiotools_convert.py index c1bcb8d943816830928dbee22364cf002e9620b0..fa555319d4a60d5c607cc0f5c185a96dbb51d121 100644 --- a/tests/test_audiotools_convert.py +++ b/tests/test_audiotools_convert.py @@ -55,7 +55,6 @@ from tests.constants import ( OUTPUT_PATH_REF, TEST_VECTOR_DIR, ) -from . import setup_test_environment def convert( @@ -126,7 +125,9 @@ def test_mono(out_fmt): @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[-3:]) def test_mono_fail(out_fmt): - with pytest.raises(ValueError, match=r".*Rendering from MONO to .* is not supported"): + with pytest.raises( + ValueError, match=r".*Rendering from MONO to .* is not supported" + ): convert("MONO", out_fmt)