diff --git a/README.md b/README.md index 07f1e541071e2f0c2c4d3263b2b88a2c7511a38f..b6efaa975a8ee11ecf3be98d77ecef7d24b9c1ca 100755 --- a/README.md +++ b/README.md @@ -193,8 +193,8 @@ input: # preprocessing: ### Target format used in rendering from input format; default = null (no rendering) # fmt: "7_1_4" - ### Flag for application of 50Hz high-pass filter; default = false - # hp50: true + ### Define mask (HP50 or 20KBP) for input signal filtering; default = null + # mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) # fs: 16000 ### Target loudness in LKFS; default = null (no loudness change applied) diff --git a/examples/TEMPLATE.yml b/examples/TEMPLATE.yml index 47f6a195247227dfb2cf0e07eba5722ad86c6e06..e29dcaef0b2448d6e9155ffaa696b38de0ff5f8d 100755 --- a/examples/TEMPLATE.yml +++ b/examples/TEMPLATE.yml @@ -64,8 +64,8 @@ input: # preprocessing: ### Target format used in rendering from input format; default = null (no rendering) # fmt: "7_1_4" - ### Flag for application of 50Hz high-pass filter; default = false - # hp50: true + ### Define mask (HP50 or 20KBP) for input signal filtering; default = null + # mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) # fs: 16000 ### Target loudness in LKFS; default = null (no loudness change applied) diff --git a/ivas_processing_scripts/audiotools/__init__.py b/ivas_processing_scripts/audiotools/__init__.py index b7ceb7d19b300829365ca52fdd81c7403369be90..b4d7aa1955d49343c87daa498ad28c3c13f11d17 100755 --- a/ivas_processing_scripts/audiotools/__init__.py +++ b/ivas_processing_scripts/audiotools/__init__.py @@ -79,10 +79,11 @@ def add_processing_args(group, input=True): default=None, ) group.add_argument( - f"-{ps}hp", - f"--{p}_hp50", - help="Apply 50 Hz high-pass filtering (default = %(default)s)", - action="store_true", + f"-{ps}mk", + f"--{p}_mask", + type=str, + help="Apply filtering with mask ((HP50, 20KBP or None; default = %(default)s)", + default=None, ) group.add_argument( f"-{ps}w", diff --git a/ivas_processing_scripts/audiotools/constants.py b/ivas_processing_scripts/audiotools/constants.py index c3af9d29952ea4069cd51060e1d5e9c2191353a0..f9f020c80ba399d85dcf4ee7963641716a410c23 100755 --- a/ivas_processing_scripts/audiotools/constants.py +++ b/ivas_processing_scripts/audiotools/constants.py @@ -692,6 +692,7 @@ DELAY_COMPENSATION_FOR_FILTERING = { "down": 145, }, "MSIN": 92, + "20KBP": 200, "LP1p5": 322, "LP35": 232, "LP7": 117, diff --git a/ivas_processing_scripts/audiotools/convert/__init__.py b/ivas_processing_scripts/audiotools/convert/__init__.py index 024faa47bb9511076cc7cc03ce8b56254f3b145f..9698dd4f56b0b8686485ef739296f0f7d6a3c3f3 100755 --- a/ivas_processing_scripts/audiotools/convert/__init__.py +++ b/ivas_processing_scripts/audiotools/convert/__init__.py @@ -43,8 +43,8 @@ from ivas_processing_scripts.audiotools.convert.scenebased import convert_sceneb 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, + maskfilter_itu, resample_itu, ) from ivas_processing_scripts.audiotools.wrappers.p50fbmnru import p50fbmnru @@ -133,7 +133,7 @@ def convert( in_delay: Optional[float] = None, in_fs: Optional[int] = None, in_cutoff: Optional[int] = None, - in_hp50: Optional[bool] = None, + in_mask: Optional[str] = None, in_window: Optional[list] = None, in_loudness: Optional[float] = None, in_loudness_fmt: Optional[str] = None, @@ -142,7 +142,7 @@ def convert( out_delay: Optional[float] = None, out_fs: Optional[int] = None, out_cutoff: Optional[int] = None, - out_hp50: Optional[bool] = None, + out_mask: Optional[str] = None, out_window: Optional[list] = None, out_loudness: Optional[float] = None, out_loudness_fmt: Optional[str] = None, @@ -162,7 +162,7 @@ def convert( delay=in_delay, fs=in_fs, fc=in_cutoff, - hp50=in_hp50, + mask=in_mask, window=in_window, loudness=in_loudness, loudness_fmt=in_loudness_fmt, @@ -180,7 +180,7 @@ def convert( delay=out_delay, fs=out_fs, fc=out_cutoff, - hp50=out_hp50, + mask=out_mask, window=out_window, loudness=out_loudness, loudness_fmt=out_loudness_fmt, @@ -198,7 +198,7 @@ def process_audio( delay: Optional[float] = None, fs: Optional[int] = None, fc: Optional[int] = None, - hp50: Optional[bool] = False, + mask: Optional[str] = None, window: Optional[float] = None, loudness: Optional[float] = None, loudness_fmt: Optional[str] = None, @@ -232,11 +232,11 @@ def process_audio( logger.debug(f"Windowing audio with {window} ms Hann window") x.audio = audioarray.window(x.audio, x.fs, window) - """high-pass (50 Hz) filtering""" - if hp50: + """mask filtering""" + if mask is not None: if logger: - logger.debug("Applying 50 Hz high-pass filter using ITU STL filter") - x.audio = hp50filter_itu(x) + logger.debug("Applying mask filter using ITU STL filter") + x.audio = maskfilter_itu(x, mask) """resampling""" if x.fs != fs: diff --git a/ivas_processing_scripts/audiotools/wrappers/filter.py b/ivas_processing_scripts/audiotools/wrappers/filter.py index 9be957586c95937c73c71523d9395345e0d27daf..426a0f2c0598598943a857a105b72fdc102d55e5 100755 --- a/ivas_processing_scripts/audiotools/wrappers/filter.py +++ b/ivas_processing_scripts/audiotools/wrappers/filter.py @@ -291,6 +291,88 @@ def hp50filter_itu( return y +def kbp20filter_itu( + x: Audio, +) -> np.ndarray: + """ + 20Hz to 20kHz bandpass filter for multi-channel audio array + + Parameters + ---------- + x: Audio + Input audio + + Returns + ------- + y: np.ndarray + Output band-pass filtered array + """ + + # set filter type and check if sampling rate is supported + old_fs = None + tmp = copy(x) + if x.fs == 48000: + flt_type = "20KBP" + else: + # resample if samplingrate is not supported + warn( + f"Filter type 20KBP only supported for 48kHz samlingrate, not for {x.fs}Hz -> resampling" + ) + flt_type = "20KBP" + old_fs = x.fs + tmp.audio = resample_itu(tmp, 48000) + tmp.fs = 48000 + + # don't apply band-pass filtering to LFE channel + if isinstance(x, ChannelBasedAudio): + skip_channel = x.lfe_index + else: + skip_channel = None + + # apply filter + y = filter_itu(tmp, flt_type=flt_type, skip_channel=skip_channel) + + # delay compensation + y = delay_compensation(y, flt_type=flt_type, fs=tmp.fs) + + # reverse resampling + if old_fs: + tmp.audio = y + y = resample_itu(tmp, old_fs) + + return y + + +def maskfilter_itu( + x: Audio, + mask: str, +) -> np.ndarray: + """ + Mask filter for multi-channel audio array + + Parameters + ---------- + x: Audio + Input audio + mask: str + Name of mask to be applied + + Returns + ------- + y: np.ndarray + Output filtered array + """ + + if mask == "HP50": + y = hp50filter_itu(x) + elif mask == "20KBP": + y = kbp20filter_itu(x) + else: + raise ValueError("Invalid mask filter defined") + + return y + + def resample_itu( x: Audio, fs_new: int, diff --git a/ivas_processing_scripts/audiotools/wrappers/gen_patt.py b/ivas_processing_scripts/audiotools/wrappers/gen_patt.py index f801b07b9e3edbab53831f1606477e7d06e7c764..d8737ef408e0e48690363aefc019b5cf34c8ee3c 100644 --- a/ivas_processing_scripts/audiotools/wrappers/gen_patt.py +++ b/ivas_processing_scripts/audiotools/wrappers/gen_patt.py @@ -138,7 +138,7 @@ def create_error_pattern( gen_patt(100, "ep.g192", 5, working_dir=tmp_dir_test) if not tmp_sta_file_test.exists(): raise RuntimeError( - "Used version of gen-patt was detected to be faulty (unable to write \"sta\"-file). See bin/README.md for details." + 'Used version of gen-patt was detected to be faulty (unable to write "sta"-file). See bin/README.md for details.' ) with TemporaryDirectory() as tmp_dir: diff --git a/ivas_processing_scripts/constants.py b/ivas_processing_scripts/constants.py index c273101601f7b1f8ad1c158cf2eda8bd05ed2d81..fbadd5238c567fa4b82294dffa3f1e40ce137fe1 100755 --- a/ivas_processing_scripts/constants.py +++ b/ivas_processing_scripts/constants.py @@ -63,7 +63,7 @@ DEFAULT_CONFIG = { "metadata_path": None, # postprocessing "postprocessing": { - "hp50": False, + "mask": None, "limit": False, }, } diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 027ac4472b2e6310a4a8fca6ceaed5893a20f6ec..64945dcee2fe26a27cd15292c39d2af43fb39a7e 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -115,7 +115,7 @@ def get_preprocessing(cfg: TestConfig) -> dict: "in_window": pre_cfg.get("window"), "in_loudness": pre_cfg.get("loudness"), "in_loudness_fmt": pre_cfg.get("loudness_fmt"), - "in_hp50": pre_cfg.get("hp50", False), + "in_mask": pre_cfg.get("mask", None), "multiprocessing": cfg.multiprocessing, } ) @@ -163,7 +163,7 @@ def get_preprocessing_2(cfg: TestConfig) -> dict: "preamble": pre2_cfg.get("preamble", 0), "pad_noise_preamble": pre2_cfg.get("preamble_noise", False), "background_noise": background, - "in_hp50": pre2_cfg.get("hp50", False), + "in_mask": pre2_cfg.get("mask", None), "multiprocessing": cfg.multiprocessing, } ) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 0d2097fa04d11555c4ad0866f9dcd223a2420674..649aa882f328799d58fa7052af4e299272ec556a 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -477,7 +477,7 @@ def preprocess_background_noise(cfg): output=output_audio, in_fs=input_audio.fs, out_fs=out_fs, - in_hp50=cfg.pre.in_hp50, + in_mask=cfg.pre.in_mask, ) # save result in cfg diff --git a/tests/data/test_ISM.yml b/tests/data/test_ISM.yml index 6be2b37766db1dade33d22d0fa6fa8176c023405..8543d18031bf35f92f8f99028356ec8d3386a257 100644 --- a/tests/data/test_ISM.yml +++ b/tests/data/test_ISM.yml @@ -71,6 +71,8 @@ input: preprocessing: ### Target format used in rendering from input format; default = null (no rendering) # fmt: "7_1_4" + ### Define mask (HP50 or 20KBP) for input signal filtering; default = null + # mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) # fs: 16000 ### Target loudness in LKFS; default = null (no loudness change applied) diff --git a/tests/data/test_MC.yml b/tests/data/test_MC.yml index 81cb34467afbcc1a7e335aa6868efedb8bd9a38a..414c2cdf5a65f6db621595330e1e74b1b5e6558b 100644 --- a/tests/data/test_MC.yml +++ b/tests/data/test_MC.yml @@ -68,6 +68,8 @@ input: preprocessing: ### Target format used in rendering from input format; default = null (no rendering) fmt: "7_1_4" + ### Define mask (HP50 or 20KBP) for input signal filtering; default = null + # mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) fs: 16000 ### Target loudness in LKFS; default = null (no loudness change applied) diff --git a/tests/data/test_SBA.yml b/tests/data/test_SBA.yml index da243a2142c283d023bf7320b0cb2c7101bb5b3a..2fc2adfe6b46f78ec589b9b8b2b86e422f16415c 100644 --- a/tests/data/test_SBA.yml +++ b/tests/data/test_SBA.yml @@ -65,11 +65,11 @@ input: ################################################ ### Pre-processing step performed prior to core processing for all conditions ### If not defined, preprocessing step is skipped -# preprocessing: +preprocessing: ### Target format used in rendering from input format; default = null (no rendering) # fmt: "7_1_4" - ### Flag for application of 50Hz high-pass filter; default = false - hp50: true + ### Define mask (HP50 or 20KBP) for input signal filtering; default = null + mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) # fs: 16000 ### Target loudness in LKFS; default = null (no loudness change applied)