diff --git a/.gitignore b/.gitignore index 849ee6b3fd1fb93db2d5e9902ec5dd28a42c1b52..a1261e3c799eb69e851e8bc057f45a71320e3e51 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ venv/ *.pcm *.bs *.192 - +mc.double diff --git a/README.md b/README.md index d6fa945621605acd47dc6edf1ee91f86e3b9b9bd..d70343e2366a7d862098e97a777583ff5eb07b5e 100755 --- a/README.md +++ b/README.md @@ -53,12 +53,16 @@ The `ivas_processing_scripts` module helps to quickly setup listening tests with This module may be used by executing the top level python module i.e. `python -m ivas_processing_scripts CONFIG.YML`. -## Configuration file +## Configuration file for processing module The processing module can be configured to set up a test via a YAML configuration file. YAML is a superset of JSON, however unlike JSON comments are permitted, which allows for the addition of useful information in the configuration file. +## Configuration file for binaries/executables + +The user can specify custom binary paths and names via a YAML configuration file called [_binary_paths.yml_](ivas_processing_scripts/binary_paths.yml). More information on usage can be found in the comments mentioned in the file. + ## YAML reference A read through of the YAML reference card is highly recommended. This can be found here: diff --git a/examples/TEMPLATE.yml b/examples/TEMPLATE.yml index 8c5fdd8e9e0df61640a48cb16147c03ff3accd21..441250aeba3ff29dbfc26b526908c209a39154e6 100755 --- a/examples/TEMPLATE.yml +++ b/examples/TEMPLATE.yml @@ -95,6 +95,8 @@ input: ### Specify the concatenation order in a list of strings. If not specified, the concatenation order would be ### as per the filesystem on the users' device ### Should only be used if concatenate_input = true + ### Specify the filename with extension. + ### For example, concatenation_order: ["file3.wav", "file1.wav", "file4.wav", "file2.wav"] # concatenation_order: [] ### Specify preamble duration in ms; default = 0 # preamble: 10000 diff --git a/ivas_processing_scripts/audiotools/wrappers/bs1770.py b/ivas_processing_scripts/audiotools/wrappers/bs1770.py index a047c339d76c43a63013a4fbb73957d752800244..fe756c07d90a4f6f971bcf72472a5a05b3f379e1 100755 --- a/ivas_processing_scripts/audiotools/wrappers/bs1770.py +++ b/ivas_processing_scripts/audiotools/wrappers/bs1770.py @@ -42,6 +42,7 @@ import numpy as np from ivas_processing_scripts.audiotools import audio, convert from ivas_processing_scripts.audiotools.audiofile import write from ivas_processing_scripts.audiotools.wrappers.filter import resample_itu +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, get_devnull, run logger = logging.getLogger("__main__") @@ -72,7 +73,13 @@ def bs1770demo( null_file = get_devnull() - binary = find_binary("bs1770demo") + if "bs1770demo" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["bs1770demo"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["bs1770demo"].parent, + ) + else: + binary = find_binary("bs1770demo") if not isinstance(input, audio.BinauralAudio) and not isinstance( input, audio.ChannelBasedAudio diff --git a/ivas_processing_scripts/audiotools/wrappers/eid_xor.py b/ivas_processing_scripts/audiotools/wrappers/eid_xor.py index 72fb5ce2f361d726513e6b119fca95fb2f715570..86075b9514bf8e285f61fae85bd86e593befea64 100644 --- a/ivas_processing_scripts/audiotools/wrappers/eid_xor.py +++ b/ivas_processing_scripts/audiotools/wrappers/eid_xor.py @@ -35,6 +35,7 @@ from pathlib import Path from typing import Optional, Union from ivas_processing_scripts.audiotools.wrappers.gen_patt import create_error_pattern +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run @@ -57,7 +58,13 @@ def eid_xor( """ # find binary - binary = find_binary("eid-xor") + if "eid-xor" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["eid-xor"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["eid-xor"].parent, + ) + else: + binary = find_binary("eid-xor") # check for valid inputs if not Path(in_bitstream).is_file(): diff --git a/ivas_processing_scripts/audiotools/wrappers/esdru.py b/ivas_processing_scripts/audiotools/wrappers/esdru.py index 4e0dfbea812a5a2e0aed97e229cad26ebbd5777b..10c1719c5a02348f2787fe2dd277da6076d3fb7f 100755 --- a/ivas_processing_scripts/audiotools/wrappers/esdru.py +++ b/ivas_processing_scripts/audiotools/wrappers/esdru.py @@ -38,6 +38,7 @@ import numpy as np from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import read, write +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run @@ -69,8 +70,13 @@ def esdru( output: np.ndarray Output array (16 bit Stereo PCM) """ - - binary = find_binary("esdru") + if "esdru" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["esdru"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["esdru"].parent, + ) + else: + binary = find_binary("esdru") if not isinstance(input, audio.BinauralAudio) and not input.name == "STEREO": raise Exception( diff --git a/ivas_processing_scripts/audiotools/wrappers/filter.py b/ivas_processing_scripts/audiotools/wrappers/filter.py index 1efbf9be0740f979a2ac2864a23408575ef82ae5..9be957586c95937c73c71523d9395345e0d27daf 100755 --- a/ivas_processing_scripts/audiotools/wrappers/filter.py +++ b/ivas_processing_scripts/audiotools/wrappers/filter.py @@ -42,6 +42,7 @@ import numpy as np from ivas_processing_scripts.audiotools.audio import Audio, ChannelBasedAudio from ivas_processing_scripts.audiotools.audioarray import delay_compensation from ivas_processing_scripts.audiotools.audiofile import read, write +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run FILTER_TYPES_REGEX = r"[\n][\s]{3}[A-Z0-9]\w+\s+" @@ -88,7 +89,13 @@ def filter_itu( Output filtered array """ - binary = find_binary("filter") + if "filter" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["filter"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["filter"].parent, + ) + else: + binary = find_binary("filter") # check if filter type is supported tmp = run([binary], check=False) diff --git a/ivas_processing_scripts/audiotools/wrappers/gen_patt.py b/ivas_processing_scripts/audiotools/wrappers/gen_patt.py index cfe5d5520482d3ab20faf60a7d2fa1a098b145e0..2b78d16e6dadba68460cda6817140cc79a718674 100644 --- a/ivas_processing_scripts/audiotools/wrappers/gen_patt.py +++ b/ivas_processing_scripts/audiotools/wrappers/gen_patt.py @@ -36,6 +36,7 @@ from tempfile import TemporaryDirectory from typing import Optional, Union from ivas_processing_scripts.audiotools.wrappers.random_seed import random_seed +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run ERROR_PATTERNS_DIR = Path(__file__).parent.parent.parent.joinpath("error_patterns") @@ -66,7 +67,13 @@ def gen_patt( """ # find binary - binary = find_binary("gen-patt") + if "gen-patt" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["gen-patt"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["gen-patt"].parent, + ) + else: + binary = find_binary("gen-patt") if working_dir is None: working_dir = getcwd() diff --git a/ivas_processing_scripts/audiotools/wrappers/masaRenderer.py b/ivas_processing_scripts/audiotools/wrappers/masaRenderer.py index 7b5eafda04f862df703495f4d59c4c386e3c15c2..ed0c30137f7188e90dd4a6b6d679bf62fbda42e1 100755 --- a/ivas_processing_scripts/audiotools/wrappers/masaRenderer.py +++ b/ivas_processing_scripts/audiotools/wrappers/masaRenderer.py @@ -38,6 +38,7 @@ import numpy as np from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import read, write from ivas_processing_scripts.audiotools.wrappers.filter import resample_itu +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run @@ -61,7 +62,13 @@ def masaRenderer( MASA rendered to out_fmt """ - binary = find_binary("masaRenderer") + if "masaRenderer" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["masaRenderer"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["masaRenderer"].parent, + ) + else: + binary = find_binary("masaRenderer") if out_fmt not in ["5_1", "7_1_4", "BINAURAL"]: raise ValueError(f"Output format {out_fmt} is not supported by MasaRenderer!") diff --git a/ivas_processing_scripts/audiotools/wrappers/networkSimulator.py b/ivas_processing_scripts/audiotools/wrappers/networkSimulator.py index 127391dd40e6d90d113979ecef7a5524dd579fd7..4ea84db13a6debdfc164e653cc85dc76dc52a1f0 100644 --- a/ivas_processing_scripts/audiotools/wrappers/networkSimulator.py +++ b/ivas_processing_scripts/audiotools/wrappers/networkSimulator.py @@ -35,6 +35,7 @@ import os.path from pathlib import Path from typing import Optional, Union +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run LIST_JBM_PROFILES = range(12) @@ -59,7 +60,17 @@ def validate_network_simulator( Number of frames per paket """ - if find_binary("networkSimulator_g192") is None: + if "networkSimulator_g192" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["networkSimulator_g192"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"][ + "networkSimulator_g192" + ].parent, + ) + else: + binary = find_binary("networkSimulator_g192") + + if binary is None: raise FileNotFoundError( "The network simulator binary was not found! Please check the configuration." ) @@ -113,7 +124,15 @@ def network_simulator( """ # find binary - binary = find_binary("networkSimulator_g192") + if "networkSimulator_g192" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["networkSimulator_g192"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"][ + "networkSimulator_g192" + ].parent, + ) + else: + binary = find_binary("networkSimulator_g192") # check for valid inputs if not Path(in_bitstream).is_file(): diff --git a/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py b/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py index 76601048c56de10eb085ce4eb879552371b2e570..4bc6b04676035d991b4ac39e4ac91c8cf968eab0 100755 --- a/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py +++ b/ivas_processing_scripts/audiotools/wrappers/p50fbmnru.py @@ -39,6 +39,7 @@ import numpy as np from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import read, write from ivas_processing_scripts.audiotools.wrappers.filter import resample_itu +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run @@ -63,7 +64,13 @@ def p50fbmnru( Output array """ - binary = find_binary("p50fbmnru") + if "p50fbmnru" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["p50fbmnru"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["p50fbmnru"].parent, + ) + else: + binary = find_binary("p50fbmnru") if input.fs != 48000: warn("P.50 Fullband MNRU requires a sampling rate of 48kHz.") diff --git a/ivas_processing_scripts/audiotools/wrappers/random_seed.py b/ivas_processing_scripts/audiotools/wrappers/random_seed.py index fd5b0cdd3424b856e7447ca6313cb949c91fcafd..9aea6aacb04c809bd4eed11c0791fa895a34e750 100644 --- a/ivas_processing_scripts/audiotools/wrappers/random_seed.py +++ b/ivas_processing_scripts/audiotools/wrappers/random_seed.py @@ -32,6 +32,7 @@ from typing import Optional, Tuple +from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES from ivas_processing_scripts.utils import find_binary, run @@ -59,7 +60,13 @@ def random_seed( """ # find binary - binary = find_binary("random") + if "random" in DEFAULT_CONFIG_BINARIES["binary_paths"]: + binary = find_binary( + DEFAULT_CONFIG_BINARIES["binary_paths"]["random"].name, + binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["random"].parent, + ) + else: + binary = find_binary("random") # set up command line cmd = [ diff --git a/ivas_processing_scripts/binary_paths.yml b/ivas_processing_scripts/binary_paths.yml new file mode 100644 index 0000000000000000000000000000000000000000..a0ce4f5b6793fa2d768f3999566e2ccb968807a5 --- /dev/null +++ b/ivas_processing_scripts/binary_paths.yml @@ -0,0 +1,30 @@ +--- +################################################ +# Binary paths +################################################ +### Custom binary paths and names can be specified here. +### If not defined here, the binaries in ivas_processing_scripts/bin would be used +### If binaries are neither specified here nor found in the bin folder, the scripts would look for them in $PATH +### DO NOT change the location of this file. +### DO NOT USE relative paths. The paths have to be absolute. +### DO NOT change the default keys. +### For example, if the user has renamed the 'filter' binary to 'foo' then use --> filter: path/to/binary/foo + +# ### Binary for resampling and filtering +# filter: "path/to/binary/filter_new" +# ### Binary for loudness adjustment +# bs1770demo: "path/to/binary/bs1880" +# ### Binary for MNRU +# p50fbmnru: "path/to/binary/p50fbmnru" +# ### Binary for ESDRU +# esdru: "path/to/binary/esdru" +# ### Binary for frame error pattern application +# eid-xor: "path/to/binary/eid-xor" +# ### Binary for error pattern generation +# gen-patt: "path/to/binary/gen-patt" +# ### Binary for random offset/seed generation +# random: "path/to/binary/random" +# ### Binary for JBM network similulator +# networkSimulator_g192: "path/to/binary/networkSimulator_g192" +# ### Binary for MASA rendering +# masaRenderer: "path/to/binary/masaRenderer" \ No newline at end of file diff --git a/ivas_processing_scripts/constants.py b/ivas_processing_scripts/constants.py index 7f02695706eeab181239540346f1af68318ede79..c273101601f7b1f8ad1c158cf2eda8bd05ed2d81 100755 --- a/ivas_processing_scripts/constants.py +++ b/ivas_processing_scripts/constants.py @@ -31,8 +31,9 @@ # from datetime import datetime +from pathlib import Path -from ivas_processing_scripts.utils import find_binary, get_gitsha +from ivas_processing_scripts.utils import find_binary, get_binary_paths, get_gitsha LOGGER_SUFFIX = ".log" LOGGER_FORMAT = ( @@ -83,6 +84,11 @@ DEFAULT_CONFIG_IVAS = { }, } +DEFAULT_CONFIG_BINARIES = { + "binary_paths": get_binary_paths( + Path(__file__).parent.joinpath("binary_paths.yml") + ), +} REQUIRED_KEYS = [ ("input", {"fmt"}), diff --git a/ivas_processing_scripts/utils.py b/ivas_processing_scripts/utils.py index f271ec76170c67f86fe9e926dba7cd9aa17f273f..1e21b0dba973cdf2dd73405e782743bf8700f6e7 100755 --- a/ivas_processing_scripts/utils.py +++ b/ivas_processing_scripts/utils.py @@ -41,6 +41,8 @@ from pathlib import Path from shutil import which from typing import Callable, Iterable, Optional, Union +import yaml + ALLOWED_INPUT_EXT = (".wav", ".pcm", ".txt", ".raw") BIN_DIR = Path(__file__).parent.joinpath("bin") @@ -144,16 +146,20 @@ def find_binary( binary: str, raise_error: Optional[bool] = True, logger: Optional[logging.Logger] = None, + binary_path: Optional[str] = None, ) -> Union[Path, None]: """Attempt to find and return the path to the given binary""" # prioritise binaries placed in the directory over $PATH - bin = which(binary, path=BIN_DIR) + if binary_path is not None: + bin = which(binary, path=binary_path) + else: + bin = which(binary, path=BIN_DIR) if not bin: bin = which(binary) if not bin and raise_error: raise FileNotFoundError( - f"Binary {binary} was not found in $PATH or in {BIN_DIR.absolute()}!" + f"Binary {binary} was neither found in {binary_path.absolute()} nor in {BIN_DIR.absolute()} or in $PATH!" ) elif not bin: if logger: @@ -280,3 +286,12 @@ def progressbar(iter: Iterable, width=80): yield item update(i + 1) print("\n", flush=True, file=sys.stdout) + + +def get_binary_paths(yaml_file_with_binary_paths): + with open(yaml_file_with_binary_paths, "r") as f: + data = yaml.safe_load(f) + if data is None: + return {} + else: + return {key: Path(value) for key, value in data.items()}