From cb64e215f0a61b7049406e767c7058edfc9194a7 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Wed, 24 May 2023 17:53:51 +0200 Subject: [PATCH 01/36] added decoding of unprocessed bitstream --- ivas_processing_scripts/processing/evs.py | 23 +++++++++++++++++++++- ivas_processing_scripts/processing/ivas.py | 12 ++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 0653327e..22274391 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -199,6 +199,7 @@ class EVS(Processing): # run processing split_chan_bs = [f.with_suffix(".192") for f in split_chan_files] split_chan_out = [f.with_suffix(".pcm") for f in split_chan_files] + split_chan_out_unprocessed = [f.with_suffix(".unprocessed.pcm") for f in split_chan_files] # run all encoders logger.debug(f"Running EVS encoders for {out_file.stem.split('.')[0]}") @@ -216,6 +217,8 @@ class EVS(Processing): show_progress=False, ) + # apply bitstream processing and save unprocessed bitstream + split_chan_bs_unprocessed = split_chan_bs split_chan_bs = apply_func_parallel( self.simulate_tx, zip(split_chan_files, split_chan_bs, repeat(logger)), @@ -224,7 +227,7 @@ class EVS(Processing): show_progress=False, ) - # run all decoders + # run all decoders twice with and without bitstream errors logger.debug(f"Running EVS decoders for {out_file.stem.split('.')[0]}") apply_func_parallel( self.dec, @@ -233,10 +236,21 @@ class EVS(Processing): "mt" if self.multiprocessing else None, show_progress=False, ) + if split_chan_bs_unprocessed != split_chan_bs: + apply_func_parallel( + self.dec, + zip(split_chan_bs_unprocessed, split_chan_out_unprocessed, repeat(logger)), + None, + "mt" if self.multiprocessing else None, + show_progress=False, + ) # combine the decoded channels into the output file if out_file.suffix in [".wav", ".pcm"]: combine(split_chan_out, out_file, in_fs=self.out_fs, is_planar=is_planar) + if split_chan_bs_unprocessed != split_chan_bs: + out_file_unprocessed = f"{Path(out_file.parent).joinpath(Path(out_file.name).with_suffix(''))}.unprocessed{out_file.suffix}" + combine(split_chan_out_unprocessed, out_file_unprocessed, in_fs=self.out_fs, is_planar=is_planar) # copy ISM metadata for ISM pass-through if in_meta: for idx in range(len(in_meta)): @@ -245,6 +259,13 @@ class EVS(Processing): / f"{out_file.stem.split('.')[0]}.evs{out_file.suffix}.{idx}.csv" ) copyfile(in_meta[idx], out_file_meta) + if split_chan_bs_unprocessed != split_chan_bs: + out_file_meta_unprocessed = ( + out_file.parent + / f"{out_file.stem.split('.')[0]}.evs.unprocessed{out_file.suffix}.{idx}.csv" + ) + copyfile(in_meta[idx], out_file_meta_unprocessed) + elif out_file.suffix == ".txt": raise NotImplementedError(".txt file support is WIP") # output_wav = out_file.replace(output_ext, ".wav") diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index b2cae46b..d7121d39 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -116,17 +116,19 @@ class IVAS(Processing): bitstream = out_file.with_suffix(".192") + # encode signal self.enc(in_file, bitstream, in_meta, logger) + # apply bitstream processing and save unprocessed bitstream + bitstream_unprocessed = bitstream bitstream = self.simulate_tx(in_file, bitstream, logger) + # decode twice with and without bitstream errors self.dec(bitstream, out_file, logger) + if bitstream_unprocessed != bitstream: + out_file_unprocessed = Path(f"{out_file.parent.joinpath(out_file.stem)}.unprocessed{out_file.suffix}") + self.dec(bitstream_unprocessed, out_file_unprocessed, logger) - if self.out_fmt == "EXT": - for i in range(self.in_fmt.num_channels): # TODO treffehn: check - # we need to read out_file.0.csv, out_file.1.csv ... - # self.out.object_pos = np.genfromtxt(out_file.with_suffix(f"{i}.0.csv"), delimiter=",") - ... def enc( self, -- GitLab From 0d40ea5b299c16c52443ccc14d99575376a4d73b Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 25 May 2023 12:39:33 +0200 Subject: [PATCH 02/36] added error when output directory is not empty --- ivas_processing_scripts/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index f5365de7..50c45205 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -87,6 +87,15 @@ def main(args): # parse configuration cfg = config.TestConfig(args.config) + # check if output folder is empty + if cfg.output_path.is_dir(): + file_list = [ + f.resolve().absolute() + for f in cfg.output_path.iterdir() + ] + if len(file_list) != 0: + raise ValueError("Output folder is not empty. Please delete or move files and folders.") + # set up processing chains chains.init_processing_chains(cfg) -- GitLab From 6c41824b86fa05fad770a56d95a8af5ffafdab11 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 25 May 2023 17:12:45 +0200 Subject: [PATCH 03/36] added post processing of noerror signal --- ivas_processing_scripts/processing/chains.py | 10 ++++++++++ ivas_processing_scripts/processing/evs.py | 14 +++++++------- ivas_processing_scripts/processing/ivas.py | 9 ++++----- .../processing/postprocessing.py | 11 +++++++++++ 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 99dff56b..7716051e 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -223,6 +223,7 @@ def get_processing_chain( tmp_lp_cutoff = post_cfg.get("lp_cutoff") tmp_mnru_q = None tmp_esdru_alpha = None + tx_condition = False # override / add values based on specific conditions cond_cfg = cfg.conditions_to_generate[condition] @@ -260,6 +261,9 @@ def get_processing_chain( # Frame error pattern bitstream modification if "tx" in cond_cfg.keys() or hasattr(cfg, "tx"): + # postprocess also signal without error if there is loudness scaling + if post_cfg.get("loudness"): + tx_condition = True # local specification overwrites global one if "tx" in cond_cfg.keys(): tx_cfg_tmp = cond_cfg["tx"] @@ -314,6 +318,7 @@ def get_processing_chain( "evs_lfe_9k6bps_nb": evs_lfe_9k6bps_nb, "sba_fmt": cond_cfg.get("sba_fmt", tmp_in_fmt), "use_windows_codec_binaries": cfg.use_windows_codec_binaries, + "tx_condition": tx_condition, } ) ) @@ -350,6 +355,9 @@ def get_processing_chain( # Frame error pattern bitstream modification if "tx" in cond_cfg.keys() or hasattr(cfg, "tx"): + # postprocess also signal without error if there is loudness scaling + if post_cfg.get("loudness"): + tx_condition = True # local specification overwrites global one if "tx" in cond_cfg.keys(): tx_cfg_tmp = cond_cfg["tx"] @@ -401,6 +409,7 @@ def get_processing_chain( "tx": tx_cfg, "preamble": preamble, "use_windows_codec_binaries": cfg.use_windows_codec_binaries, + "tx_condition": tx_condition, } ) ) @@ -427,6 +436,7 @@ def get_processing_chain( "multiprocessing": cfg.multiprocessing, "mnru_q": tmp_mnru_q, "esdru_alpha": tmp_esdru_alpha, + "tx_condition": tx_condition, } ) ) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 32882e76..039dc5a6 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -205,7 +205,7 @@ class EVS(Processing): # run processing split_chan_bs = [f.with_suffix(".192") for f in split_chan_files] split_chan_out = [f.with_suffix(".pcm") for f in split_chan_files] - split_chan_out_unprocessed = [f.with_suffix(".unprocessed.pcm") for f in split_chan_files] + split_chan_out_noerror = [f.with_suffix(".noerror.pcm") for f in split_chan_files] # run all encoders logger.debug(f"Running EVS encoders for {out_file.stem.split('.')[0]}") @@ -245,7 +245,7 @@ class EVS(Processing): if split_chan_bs_unprocessed != split_chan_bs: apply_func_parallel( self.dec, - zip(split_chan_bs_unprocessed, split_chan_out_unprocessed, repeat(logger)), + zip(split_chan_bs_unprocessed, split_chan_out_noerror, repeat(logger)), None, "mt" if self.multiprocessing else None, show_progress=False, @@ -254,9 +254,9 @@ class EVS(Processing): # combine the decoded channels into the output file if out_file.suffix in [".wav", ".pcm"]: combine(split_chan_out, out_file, in_fs=self.out_fs, is_planar=is_planar) - if split_chan_bs_unprocessed != split_chan_bs: - out_file_unprocessed = f"{Path(out_file.parent).joinpath(Path(out_file.name).with_suffix(''))}.unprocessed{out_file.suffix}" - combine(split_chan_out_unprocessed, out_file_unprocessed, in_fs=self.out_fs, is_planar=is_planar) + if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: + out_file_unprocessed = f"{Path(out_file.parent).joinpath(Path(out_file.name).with_suffix(''))}.noerror{out_file.suffix}" + combine(split_chan_out_noerror, out_file_unprocessed, in_fs=self.out_fs, is_planar=is_planar) # copy ISM metadata for ISM pass-through if in_meta: for idx in range(len(in_meta)): @@ -265,10 +265,10 @@ class EVS(Processing): / f"{out_file.stem.split('.')[0]}.evs{out_file.suffix}.{idx}.csv" ) copyfile(in_meta[idx], out_file_meta) - if split_chan_bs_unprocessed != split_chan_bs: + if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: out_file_meta_unprocessed = ( out_file.parent - / f"{out_file.stem.split('.')[0]}.evs.unprocessed{out_file.suffix}.{idx}.csv" + / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" ) copyfile(in_meta[idx], out_file_meta_unprocessed) diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index f49e4888..7db4f2e1 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -126,15 +126,14 @@ class IVAS(Processing): self.enc(in_file, bitstream, in_meta, logger) # apply bitstream processing and save unprocessed bitstream - bitstream_unprocessed = bitstream + bitstream_noerror = bitstream bitstream = self.simulate_tx(in_file, bitstream, logger) # decode twice with and without bitstream errors self.dec(bitstream, out_file, logger) - if bitstream_unprocessed != bitstream: - out_file_unprocessed = Path(f"{out_file.parent.joinpath(out_file.stem)}.unprocessed{out_file.suffix}") - self.dec(bitstream_unprocessed, out_file_unprocessed, logger) - + if bitstream_noerror != bitstream and self.tx_condition: + out_file_unprocessed = Path(f"{out_file.parent.joinpath(out_file.stem)}.noerror{out_file.suffix}") + self.dec(bitstream_noerror, out_file_unprocessed, logger) def enc( self, diff --git a/ivas_processing_scripts/processing/postprocessing.py b/ivas_processing_scripts/processing/postprocessing.py index 1d2f2240..72e5d2f2 100755 --- a/ivas_processing_scripts/processing/postprocessing.py +++ b/ivas_processing_scripts/processing/postprocessing.py @@ -52,3 +52,14 @@ class Postprocessing(Processing): convert.convert_file( in_file, out_file, logger=logger, in_meta=in_meta, **self.__dict__ ) + # additional postprocessing of signal without error modification + if self.tx_condition: + in_file_no_error = Path(f"{in_file.with_suffix('')}.noerror.wav") + out_file_no_error = Path(f"{out_file.with_suffix('')}.noerror.wav") + if in_meta: + in_meta_no_error = None # TODO + else: + in_meta_no_error = None + convert.convert_file( + in_file_no_error, out_file_no_error, logger=logger, in_meta=in_meta_no_error, **self.__dict__ + ) -- GitLab From 749766c9d6dbd6eed9763a1e43e978095a89925b Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 25 May 2023 19:18:00 +0200 Subject: [PATCH 04/36] added processing splitting scaling --- ivas_processing_scripts/__init__.py | 9 - ivas_processing_scripts/processing/chains.py | 21 +- .../processing/preprocessing_2.py | 1 - .../processing/processing.py | 219 ++++++++---------- .../processing_splitting_scaling.py | 103 ++++++++ 5 files changed, 213 insertions(+), 140 deletions(-) create mode 100644 ivas_processing_scripts/processing/processing_splitting_scaling.py diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 50c45205..0e9c927f 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -50,7 +50,6 @@ from ivas_processing_scripts.processing.processing import ( process_item, rename_generated_conditions, reorder_items_list, - reverse_process_2, scale_resulting_files, ) from ivas_processing_scripts.utils import DirManager, apply_func_parallel @@ -184,14 +183,6 @@ def main(args): "mp" if cfg.multiprocessing else None, ) - # remove preamble and split signals - if hasattr(cfg, "preprocessing_2"): - reverse_process_2(cfg, logger) - - # scale individual files - if cfg.postprocessing.get("loudness", False): - scale_resulting_files(cfg, logger) - # rename output with condition name if cfg.condition_in_output_filename: rename_generated_conditions(cfg.output_path) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 7716051e..ce1c6861 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -39,6 +39,7 @@ from ivas_processing_scripts.processing.ivas import IVAS, validate_sba_fmt from ivas_processing_scripts.processing.postprocessing import Postprocessing from ivas_processing_scripts.processing.preprocessing import Preprocessing from ivas_processing_scripts.processing.preprocessing_2 import Preprocessing2 +from ivas_processing_scripts.processing.processing_splitting_scaling import Processing_splitting_scaling from ivas_processing_scripts.utils import get_abs_path, list_audio @@ -54,9 +55,6 @@ def init_processing_chains(cfg: TestConfig) -> None: # other processing chains for cond_name, cond_cfg in cfg.conditions_to_generate.items(): bitrates = cond_cfg.get("bitrates") - # TODO we may need to change this to ensure it is only one value for IVAS and a possible list for EVS - # condition naming will also need to be checked since we rename to {cond_name}_{bitrate} - # this may not be desired if bitrates is not None and len(bitrates) > 1: multiple_bitrates_flag = True else: @@ -214,6 +212,7 @@ def get_processing_chain( # get pre and post processing configurations pre_cfg = getattr(cfg, "preprocessing", {}) post_cfg = cfg.postprocessing + pre2_cfg = getattr(cfg, "preprocessing_2", {}) # default to input values if preprocessing was not requested tmp_in_fs = pre_cfg.get("fs", cfg.input.get("fs")) @@ -440,5 +439,21 @@ def get_processing_chain( } ) ) + # add splitting and scaling for all conditions + chain["processes"].append( + Processing_splitting_scaling( + { + "fs": post_cfg["fs"], + "in_fmt": post_cfg["fmt"], + "out_fmt": post_cfg["fmt"], # no rendering here + "concatenate_input": pre2_cfg.get("concatenate_input", False), + "preamble": pre2_cfg.get("preamble", 0), + "repeat_signal": pre2_cfg.get("repeat_signal", False), + "loudness": post_cfg.get("loudness", None), + "loudness_fmt": post_cfg.get("loudness_fmt", None), + "tx_condition": tx_condition, + } + ) + ) return chain diff --git a/ivas_processing_scripts/processing/preprocessing_2.py b/ivas_processing_scripts/processing/preprocessing_2.py index b0f60519..7478ec01 100644 --- a/ivas_processing_scripts/processing/preprocessing_2.py +++ b/ivas_processing_scripts/processing/preprocessing_2.py @@ -65,7 +65,6 @@ class Preprocessing2(Processing): ) # add preamble - # also apply preamble to ISM metadata if self.in_fmt.startswith("ISM"): if not self.preamble: diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 0f74e71f..15da0874 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -45,10 +45,10 @@ from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import ( concat, read, - split, trim, write, ) +from ivas_processing_scripts.audiotools.audioarray import window from ivas_processing_scripts.audiotools.convert.__init__ import convert from ivas_processing_scripts.audiotools.metadata import ( add_remove_preamble, @@ -172,60 +172,54 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger): logger.info(f"Splits written to file {cfg.concat_file.with_suffix('.splits.log')}") -def concat_teardown(cfg: TestConfig, logger: logging.Logger): - if not cfg.splits: - raise ValueError("Splitting not possible without split marker") - - output_format = cfg.postprocessing["fmt"] +def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): - out_files = [] - out_meta = [] - - logger.info(f"Splitting output file in directory {cfg.output_path}") + if not splits: + raise ValueError("Splitting not possible without split marker") + logger.debug("Split files") # if sampling rate changed, adjust splits - fs_new = float(cfg.postprocessing["fs"]) - fs_old = float(cfg.pre2.in_fs) + fs_new = float(fs) + fs_old = float(in_fs) relative_fs_change = fs_new / fs_old new_splits = [] - for split_i in cfg.splits: + for split_i in splits: new_splits.append(int(float(split_i) * relative_fs_change)) - cfg.splits = new_splits - - 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, - in_fs=cfg.postprocessing["fs"], - ) + splits = new_splits - logger.debug( - f"Resulting split files condition {odir.name}: {', '.join([str(op) for op in out_paths])}" - ) - out_files.append(out_paths) + split_old = 0 + split_signals = [] + for idx, split in enumerate(splits): + # split + y = x[split_old:split, :] - # split ISM metadata - if output_format.startswith("ISM"): - for odir in cfg.out_dirs: - path_input = odir / cfg.items_list[0].name - out_meta_paths = split_meta_in_file( - path_input, - odir, - cfg.split_names, - cfg.splits, - output_format, - meta_files=cfg.metadata_path[0], - ) - out_meta.append(out_meta_paths) + # windowing + y = window(y) + + # add signal to list + split_signals.append(y) - # remove concatenated file - if cfg.delete_tmp: - cfg.concat_file.unlink(missing_ok=True) + split_old = split - return out_files, out_meta + # split ISM metadata + if out_fmt.startswith("ISM"): # TODO + # for odir in cfg.out_dirs: + # path_input = odir / cfg.items_list[0].name + # out_meta_paths = split_meta_in_file( + # path_input, + # odir, + # cfg.split_names, + # cfg.splits, + # output_format, + # meta_files=cfg.metadata_path[0], + # ) + # out_meta.append(out_meta_paths) + split_meta = None + pass + else: + split_meta = None + + return split_signals, split_meta def preprocess(cfg, logger): @@ -322,38 +316,6 @@ def preprocess_2(cfg, logger): return -def reverse_process_2(cfg, logger): - # remove preamble and first half of signal due to repetition - if cfg.pre2.preamble or cfg.pre2.repeat_signal: - remove_preamble(cfg, logger) - - # reverse concatenation - if cfg.pre2.concatenate_input: - # write out the splits, optionally remove file - out_paths_splits, out_meta_splits = concat_teardown(cfg, logger) - else: - # if no concatenation read files from folder - out_paths_splits = [] - for out_dir in cfg.out_dirs: - list_audio_dir = list_audio(out_dir) - out_paths_splits.append(list_audio_dir) - if cfg.postprocessing["fmt"].startswith("ISM"): - out_meta_splits = [] - for i, condition in enumerate(out_paths_splits): - meta_condition = metadata_search( - cfg.out_dirs[i], - condition, - num_objects=int(cfg.postprocessing["fmt"][-1]), - ) - out_meta_splits.append(meta_condition) - else: - out_meta_splits = None - - cfg.pre2.out_paths_splits = out_paths_splits - cfg.pre2.out_meta_splits = out_meta_splits - return - - def process_item( in_file: Union[Path, str], tmp_dir: Union[Path, str], @@ -413,6 +375,7 @@ def process_item( for im in range(len(in_meta)): out_meta.append(out_dir.joinpath(f"{Path(out_file).stem}.wav.{im}.csv")) + tx_condition = False # execute each process sequentially, feed output into input of next process for p, (input, output), input_meta in zip( chain, pairwise(processing_paths), processing_paths_meta[:-1] @@ -424,6 +387,12 @@ def process_item( fh.setFormatter(logging.Formatter(LOGGER_FORMAT, datefmt=LOGGER_DATEFMT)) item_logger.addHandler(fh) + # set info about tx and loudness + try: + tx_condition = p.tx_condition + except AttributeError: + tx_condition = False + p.process(input, output, input_meta, item_logger) # copy output and metadata from final process to output file @@ -431,59 +400,55 @@ def process_item( if processing_paths_meta[-1]: for idx, ppm in enumerate(processing_paths_meta[-1]): copyfile(ppm, out_meta[idx]) + # if bitstream processing and loudness adjustment copy additional file + if tx_condition: + out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") + in_file_noerror = Path(f"{processing_paths[-1].with_suffix('')}.noerror.wav") + copyfile(in_file_noerror, out_file_noerror) + if processing_paths_meta[-1]: # TODO + for idx, ppm in enumerate(processing_paths_meta[-1]): + copyfile(ppm, out_meta[idx]) + + +def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, logger): + + # remove preamble for ISM metadata + if out_fmt.startswith("ISM"): # TODO + # # search for metadata + # meta_item = metadata_search( + # odir, [Path(item.name)], num_objects=num_channels + # ) + # metadata_array = [] + # for meta_i in meta_item: + # metadata_array.append(np.genfromtxt(meta_i, delimiter=",")) + # + # # cut first half of the metadata + # if cfg.pre2.repeat_signal: + # metadata_array = [m[int(len(m) / 2) :, :] for m in metadata_array] + # + # # remove preamble + # if cfg.pre2.preamble: + # metadata_array = add_remove_preamble( + # metadata_array, cfg.pre2.preamble, add=False + # ) + # + # # write csv files + # write_ISM_metadata_in_file( + # metadata_array, [path_input], automatic_naming=True + # ) + pass + # remove first half of signal + if repeat_signal: + logger.info("Remove first half of signal") + x = x[int(len(x) / 2):, :] -def remove_preamble(cfg, logger): - # get number of channels from output format - num_channels = audio.fromtype(cfg.postprocessing["fmt"]).num_channels - for odir in cfg.out_dirs: - for item in cfg.items_list: - path_input = odir / item.name - - # remove preamble for ISM metadata - if cfg.postprocessing["fmt"].startswith("ISM"): - # search for metadata - meta_item = metadata_search( - odir, [Path(item.name)], num_objects=num_channels - ) - metadata_array = [] - for meta_i in meta_item: - metadata_array.append(np.genfromtxt(meta_i, delimiter=",")) - - # cut first half of the metadata - if cfg.pre2.repeat_signal: - metadata_array = [m[int(len(m) / 2) :, :] for m in metadata_array] - - # remove preamble - if cfg.pre2.preamble: - metadata_array = add_remove_preamble( - metadata_array, cfg.pre2.preamble, add=False - ) - - # write csv files - write_ISM_metadata_in_file( - metadata_array, [path_input], automatic_naming=True - ) - - # read file - x, fs = read( - path_input, nchannels=num_channels, fs=cfg.postprocessing["fs"] - ) - - # remove first half of signal - if cfg.pre2.repeat_signal: - logger.info("Remove first half of signal") - x = x[int(len(x) / 2) :, :] - - # remove preamble - if cfg.pre2.preamble: - logger.info("Remove preamble") - x = trim(x, fs, (cfg.pre2.preamble, 0)) - - # write file - write(path_input, x, fs) + # remove preamble + if preamble: + logger.info("Remove preamble") + x = trim(x, fs, (preamble, 0)) - return + return x def preprocess_background_noise(cfg): diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py new file mode 100644 index 00000000..2b943431 --- /dev/null +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +# +# (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. +# + +import logging +from pathlib import Path +from itertools import repeat + +from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown, \ + scale_resulting_files +from ivas_processing_scripts.audiotools import audio +from ivas_processing_scripts.audiotools.audiofile import write, read + + +class Processing_splitting_scaling(Processing): + def __init__(self, attrs: dict): + super().__init__(attrs) + self.name = "processing_splitting_scaling" + + def process(self, in_file: Path, out_file: Path, in_meta, logger: logging.Logger): + + logger.debug(f"Processing splitting scaling configuration : {self.__dict__}") + logger.debug(f"Processing splitting scaling {in_file.absolute()}") + + # get number of channels from output format + num_channels = audio.fromtype(self.out_fmt).num_channels + # read file + x, fs = read(in_file, nchannels=num_channels, fs=self.fs) + if self.tx_condition: + in_file_noerror = Path(f"{in_file.with_suffix('')}.noerror.wav") + x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) + + # remove preamble and first half of signal due to repetition + if self.preamble or self.repeat_signal: + # TODO: ISM metadata + x = remove_preamble(x, self.out_fmt, self.fs, self.repeat_signal, self.preamble, logger) + if self.tx_condition: + # also process noerror signal + x_noerror = remove_preamble(x_noerror, self.out_fmt, self.fs, self.repeat_signal, self.preamble, logger) + + # reverse concatenation + if self.concatenate_input: + # read out splits file -> start/end, names, sampling rate + splits, split_names, split_fs = read_splits_file(in_file) + # split file + file_splits,meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) + # set new out_files + out_files = split_names # TODO + if self.tx_condition: + file_splits_noerror, meta_splits_noerror = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) + else: + out_files = [out_file] + file_splits = [x] + meta_splits = repeat(None) + if self.tx_condition: + file_splits_noerror = None + meta_splits_noerror = None # TODO + + # scale splitted files + if self.loudness: # TODO + # scale_resulting_files(cfg, logger) + pass + + # write file(s) + for of, file_s, meta_s in zip(out_files, file_splits, meta_splits): + write(of, file_s, fs) + if meta_s: + pass # TODO + if self.tx_condition: + pass # TODO + + +def read_splits_file(in_file): + # TODO + return None, None, None -- GitLab From 8e6f0d73e5ef0121496090d133adbc0d0d77c168 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 26 May 2023 13:23:34 +0200 Subject: [PATCH 05/36] added special loudness scaling --- ivas_processing_scripts/__init__.py | 1 - .../audiotools/convert/__init__.py | 2 +- .../audiotools/wrappers/bs1770.py | 71 ++-------------- .../processing/preprocessing_2.py | 2 +- .../processing/processing.py | 74 +++++----------- .../processing_splitting_scaling.py | 85 ++++++++++++++----- 6 files changed, 92 insertions(+), 143 deletions(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 0e9c927f..895851fa 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -50,7 +50,6 @@ from ivas_processing_scripts.processing.processing import ( process_item, rename_generated_conditions, reorder_items_list, - scale_resulting_files, ) from ivas_processing_scripts.utils import DirManager, apply_func_parallel diff --git a/ivas_processing_scripts/audiotools/convert/__init__.py b/ivas_processing_scripts/audiotools/convert/__init__.py index 52344705..1a06b165 100755 --- a/ivas_processing_scripts/audiotools/convert/__init__.py +++ b/ivas_processing_scripts/audiotools/convert/__init__.py @@ -273,7 +273,7 @@ def process_audio( logger.debug( f"Applying loudness adjustment to {loudness} LKFS for format {loudness_fmt} using ITU STL bs1770demo" ) - x.audio = loudness_norm(x, loudness, loudness_fmt, logger=logger) + x.audio, _ = loudness_norm(x, loudness, loudness_fmt, logger=logger) """limiting""" if limit: diff --git a/ivas_processing_scripts/audiotools/wrappers/bs1770.py b/ivas_processing_scripts/audiotools/wrappers/bs1770.py index 0d9c8ff4..f8052bc4 100755 --- a/ivas_processing_scripts/audiotools/wrappers/bs1770.py +++ b/ivas_processing_scripts/audiotools/wrappers/bs1770.py @@ -225,7 +225,7 @@ def loudness_norm( rms: Optional[bool] = False, logger: Optional[logging.Logger] = None, file_name_logging: Optional[Union[str, Path]] = None, -) -> np.ndarray: +) -> Tuple[np.ndarray, float]: """ Iterative loudness normalization using ITU-R BS.1770-4 Signal is iteratively scaled after rendering to the specified format @@ -248,13 +248,16 @@ def loudness_norm( Returns ------- - norm : Audio + norm: Audio Normalized audio + scaling_factor: float + applied scaling factor """ measured_loudness = np.inf num_iter = 1 scaled_input = copy.deepcopy(input) + scaling_factor = 1.0 # save loudness before and after scaling for the logger info loudness_before, scale_factor_new, loundness_fmt_used = get_loudness( @@ -265,6 +268,7 @@ def loudness_norm( while np.abs(measured_loudness - target_loudness) > 0.5 and num_iter <= 10: # scale input scaled_input.audio *= scale_factor_new + scaling_factor *= scale_factor_new # measure loudness and get scaling factor measured_loudness, scale_factor_new, _ = get_loudness( @@ -291,65 +295,4 @@ def loudness_norm( f"Loudness did not converge to desired value, stopping at: {loudness_after:.2f}" ) - return scaled_input.audio - - -def scale_files( - file_list: list[list[Union[Path, str]]], - fmt: str, - loudness: float, - loudness_format: Optional[str] = None, - fs: Optional[int] = 48000, - in_meta: Optional[list] = None, - logger: Optional[logging.Logger] = None, -) -> None: - """ - Scales audio files to desired loudness - - Parameters - ---------- - file_list : list[list[Union[Path, str]]] - List of file paths in a list of the condition folders - fmt: str - Audio format of files in list - loudness: float - Desired loudness level in LKFS/dBov - loudness_format: Optional[str] - Format for loudness measurement - fs: Optional[int] - Sampling rate - in_meta: Optional[list] - Metadata for ISM with same structure as file_list but one layer more - for the list of metadata for one file - logger: Optional[logging.Logger] - Logger to log loudness information - """ - - if fmt.startswith("ISM"): - if in_meta: - meta_bool = True - else: - raise ValueError("No metadata available for loudness measurement") - else: - in_meta = copy.copy(file_list) - meta_bool = False - - for folder, meta_folder in zip(file_list, in_meta): - for file, meta in zip(folder, meta_folder): - # create audio object - if meta_bool: - audio_obj = audio.fromfile(fmt, file, fs, meta) - else: - audio_obj = audio.fromfile(fmt, file, fs) - - # adjust loudness - scaled_audio = loudness_norm( - audio_obj, - loudness, - loudness_format, - logger=logger, - file_name_logging=file, - ) - - # write into file - write(file, scaled_audio, audio_obj.fs) + return scaled_input.audio, scaling_factor diff --git a/ivas_processing_scripts/processing/preprocessing_2.py b/ivas_processing_scripts/processing/preprocessing_2.py index 7478ec01..92068458 100644 --- a/ivas_processing_scripts/processing/preprocessing_2.py +++ b/ivas_processing_scripts/processing/preprocessing_2.py @@ -170,7 +170,7 @@ class Preprocessing2(Processing): logger.debug( f"Scaling of background noise to {self.background_noise['snr']}dB SNR" ) - noise_object.audio = loudness_norm( + noise_object.audio, _ = loudness_norm( noise_object, loudness_noise, out_format, diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 15da0874..456713b6 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -57,7 +57,6 @@ from ivas_processing_scripts.audiotools.metadata import ( split_meta_in_file, write_ISM_metadata_in_file, ) -from ivas_processing_scripts.audiotools.wrappers.bs1770 import scale_files from ivas_processing_scripts.constants import LOGGER_DATEFMT, LOGGER_FORMAT from ivas_processing_scripts.processing.config import TestConfig from ivas_processing_scripts.utils import apply_func_parallel, list_audio, pairwise @@ -160,14 +159,11 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger): # set input to the concatenated file we have just written to the output dir cfg.items_list = [cfg.concat_file] - # save input sampling rate for splitting at the end - cfg.pre2.in_fs = fs - # write out splits with open(cfg.concat_file.with_suffix(".splits.log"), "w") as f: print(", ".join([str(s) for s in cfg.splits]), file=f) print(", ".join([str(sn) for sn in cfg.split_names]), file=f) - print(", ".join([str(i.stem) for i in cfg.items_list]), file=f) + print(f"{fs}", file=f) logger.info(f"Splits written to file {cfg.concat_file.with_suffix('.splits.log')}") @@ -176,7 +172,8 @@ def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): if not splits: raise ValueError("Splitting not possible without split marker") - logger.debug("Split files") + if logger: + logger.debug("Split files") # if sampling rate changed, adjust splits fs_new = float(fs) @@ -214,10 +211,10 @@ def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): # meta_files=cfg.metadata_path[0], # ) # out_meta.append(out_meta_paths) - split_meta = None + split_meta = repeat(None) pass else: - split_meta = None + split_meta = repeat(None) return split_signals, split_meta @@ -396,18 +393,19 @@ def process_item( p.process(input, output, input_meta, item_logger) # copy output and metadata from final process to output file - copyfile(processing_paths[-1], out_file) - if processing_paths_meta[-1]: - for idx, ppm in enumerate(processing_paths_meta[-1]): - copyfile(ppm, out_meta[idx]) - # if bitstream processing and loudness adjustment copy additional file - if tx_condition: - out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") - in_file_noerror = Path(f"{processing_paths[-1].with_suffix('')}.noerror.wav") - copyfile(in_file_noerror, out_file_noerror) - if processing_paths_meta[-1]: # TODO + if not chain[-1].name == "processing_splitting_scaling": + copyfile(processing_paths[-1], out_file) + if processing_paths_meta[-1]: for idx, ppm in enumerate(processing_paths_meta[-1]): copyfile(ppm, out_meta[idx]) + # if bitstream processing and loudness adjustment copy additional file + if tx_condition: + out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") + in_file_noerror = Path(f"{processing_paths[-1].with_suffix('')}.noerror.wav") + copyfile(in_file_noerror, out_file_noerror) + if processing_paths_meta[-1]: # TODO + for idx, ppm in enumerate(processing_paths_meta[-1]): + copyfile(ppm, out_meta[idx]) def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, logger): @@ -440,12 +438,14 @@ def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, logger): # remove first half of signal if repeat_signal: - logger.info("Remove first half of signal") + if logger: + logger.info("Remove first half of signal") x = x[int(len(x) / 2):, :] # remove preamble if preamble: - logger.info("Remove preamble") + if logger: + logger.info("Remove preamble") x = trim(x, fs, (preamble, 0)) return x @@ -551,37 +551,3 @@ def rename_generated_conditions(output_path: Path): new_filename = f"{file_path.stem}.{subdirectory.name}{file_path.suffix}" file_path.rename(subdirectory / new_filename) - -def scale_resulting_files(cfg, logger): - if hasattr(cfg, "preprocessing_2"): - out_paths_splits = cfg.pre2.out_paths_splits - out_meta_splits = cfg.pre2.out_meta_splits - else: - num_obj = audio.fromtype(cfg.postprocessing["fmt"]).num_channels - out_paths_splits = [] - if isinstance( - audio.fromtype(cfg.postprocessing["fmt"]), audio.ObjectBasedAudio - ): - out_meta_splits = [] - else: - out_meta_splits = None - item_names = [Path(i.name) for i in cfg.items_list] - for out_dir in cfg.out_dirs: - condition_list = [] - for item in item_names: - condition_list.append(out_dir.joinpath(item)) - out_paths_splits.append(condition_list) - if isinstance( - audio.fromtype(cfg.postprocessing["fmt"]), audio.ObjectBasedAudio - ): - out_meta_splits.append(metadata_search(out_dir, item_names, num_obj)) - - scale_files( - out_paths_splits, - cfg.postprocessing["fmt"], - cfg.postprocessing["loudness"], - cfg.postprocessing.get("loudness_fmt", None), - cfg.postprocessing["fs"], - out_meta_splits, - logger, - ) diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 2b943431..532a0f65 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -34,10 +34,10 @@ import logging from pathlib import Path from itertools import repeat -from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown, \ - scale_resulting_files +from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import write, read +from ivas_processing_scripts.audiotools.wrappers.bs1770 import loudness_norm class Processing_splitting_scaling(Processing): @@ -56,24 +56,52 @@ class Processing_splitting_scaling(Processing): x, fs = read(in_file, nchannels=num_channels, fs=self.fs) if self.tx_condition: in_file_noerror = Path(f"{in_file.with_suffix('')}.noerror.wav") + out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) + # cut preamble and split file + out_files, file_splits, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, False, logger) + if self.tx_condition: + out_files_noerror, file_splits_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, True) + + # scale splitted files + if self.loudness: + if self.tx_condition: + # do special scaling -> measure noerror loudness and apply scaling to signal with error + scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, logger) + file_splits = [f*loud for f, loud in zip(file_splits, scaling_splits)] + else: + file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, logger) + + # write file(s) + for of, file_s, meta_s in zip(out_files, file_splits, meta_splits): + write(of, file_s, fs) + if meta_s: + pass # TODO + + # copy files to output folder + # TODO + + def revert_preamble_concatenation(self, x, fs, in_file, out_file, noerror=False, logger=None): # remove preamble and first half of signal due to repetition if self.preamble or self.repeat_signal: # TODO: ISM metadata x = remove_preamble(x, self.out_fmt, self.fs, self.repeat_signal, self.preamble, logger) - if self.tx_condition: - # also process noerror signal - x_noerror = remove_preamble(x_noerror, self.out_fmt, self.fs, self.repeat_signal, self.preamble, logger) # reverse concatenation if self.concatenate_input: # read out splits file -> start/end, names, sampling rate - splits, split_names, split_fs = read_splits_file(in_file) + if noerror: + splits_info_file = Path( + f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(Path(in_file.stem).stem).stem)}.splits.log") + else: + splits_info_file = Path( + f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(in_file.stem).stem)}.splits.log") + splits, split_names, split_fs = read_splits_file(splits_info_file) # split file - file_splits,meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) + file_splits, meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) # set new out_files - out_files = split_names # TODO + out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] if self.tx_condition: file_splits_noerror, meta_splits_noerror = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) else: @@ -84,20 +112,33 @@ class Processing_splitting_scaling(Processing): file_splits_noerror = None meta_splits_noerror = None # TODO - # scale splitted files - if self.loudness: # TODO - # scale_resulting_files(cfg, logger) - pass + return out_files, file_splits, meta_splits - # write file(s) - for of, file_s, meta_s in zip(out_files, file_splits, meta_splits): - write(of, file_s, fs) - if meta_s: - pass # TODO - if self.tx_condition: - pass # TODO + +def read_splits_file(splits_file): + """Read out splitting information from split log in preproceesing 2 temp folder""" + with open(splits_file, "r") as f: + splits = f.readline()[:-1].split(", ") + names = f.readline()[:-1].split(", ") + fs = f.readline()[:-1] + return splits, names, fs + + +def adjust_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, logger=None): + scaled_signals = [] + for f in file_splits: + audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) + scaled_signal, _ = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) + scaled_signals.append(scaled_signal) + return scaled_signals -def read_splits_file(in_file): - # TODO - return None, None, None +def measure_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, logger): + if logger: + logger.debug("Apply special scaling for bitstream error conditions") + scaling_splits = [] + for f in file_splits: + audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) + _, scale_factor = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) + scaling_splits.append(scale_factor) + return scaling_splits -- GitLab From 76c223cd9f4bf1b9ae0e59fdd77e342b1cf5cefd Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 26 May 2023 14:28:03 +0200 Subject: [PATCH 06/36] works mostly but not for ISM --- .../processing_splitting_scaling.py | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 532a0f65..0bd35057 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 - +import copy # # (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., @@ -33,6 +33,7 @@ import logging from pathlib import Path from itertools import repeat +import re from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown from ivas_processing_scripts.audiotools import audio @@ -73,15 +74,25 @@ class Processing_splitting_scaling(Processing): else: file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, logger) - # write file(s) - for of, file_s, meta_s in zip(out_files, file_splits, meta_splits): + # derive output folder names + out_out_files = [] + for f in out_files: + regex_filter = r"[/\\][t][m][p][_]\w+[/\\]" + tmp_name = re.search(regex_filter, str(f)).group().strip()[1:-1] + out_name = tmp_name.replace("tmp_", "") + f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) + out_out_files.append(f_out) + if meta_splits: + # TODO + pass + + # write file(s) in tmp and output folder + for of, oof, file_s, meta_s in zip(out_files, out_out_files, file_splits, meta_splits): write(of, file_s, fs) + write(oof, file_s, fs) if meta_s: pass # TODO - # copy files to output folder - # TODO - def revert_preamble_concatenation(self, x, fs, in_file, out_file, noerror=False, logger=None): # remove preamble and first half of signal due to repetition if self.preamble or self.repeat_signal: -- GitLab From a484858437b7bd698fd3bd5affb6ea05b13687b7 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 26 May 2023 14:57:36 +0200 Subject: [PATCH 07/36] changed renaming of files at the end --- ivas_processing_scripts/__init__.py | 5 ----- ivas_processing_scripts/processing/chains.py | 1 + .../processing/processing.py | 18 ------------------ .../processing/processing_splitting_scaling.py | 5 ++++- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 895851fa..b6378f32 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -48,7 +48,6 @@ from ivas_processing_scripts.processing.processing import ( preprocess_2, preprocess_background_noise, process_item, - rename_generated_conditions, reorder_items_list, ) from ivas_processing_scripts.utils import DirManager, apply_func_parallel @@ -182,10 +181,6 @@ def main(args): "mp" if cfg.multiprocessing else None, ) - # rename output with condition name - if cfg.condition_in_output_filename: - rename_generated_conditions(cfg.output_path) - # copy configuration to output directory with open(cfg.output_path.joinpath(f"{cfg.name}.yml"), "w") as f: yaml.safe_dump(cfg._yaml_dump, f) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index ce1c6861..68594d9e 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -452,6 +452,7 @@ def get_processing_chain( "loudness": post_cfg.get("loudness", None), "loudness_fmt": post_cfg.get("loudness_fmt", None), "tx_condition": tx_condition, + "condition_in_output_filename": cfg.condition_in_output_filename, } ) ) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 456713b6..f7f1b714 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -533,21 +533,3 @@ def multiple_of_frame_size( ) -def rename_generated_conditions(output_path: Path): - """ - Rename the output files. Only renames the files in directories that contain "cXX" in thier names. - The "XX" in "cXX" stands for the condition number, for example "c01" - - Parameters - ---------- - output_path: Path - Path to output directory - """ - directory = output_path - pattern = re.compile(r"^c\d{2}") - for subdirectory in directory.iterdir(): - if subdirectory.is_dir() and pattern.match(subdirectory.name): - for file_path in subdirectory.iterdir(): - new_filename = f"{file_path.stem}.{subdirectory.name}{file_path.suffix}" - file_path.rename(subdirectory / new_filename) - diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 0bd35057..bc3c977b 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -80,7 +80,10 @@ class Processing_splitting_scaling(Processing): regex_filter = r"[/\\][t][m][p][_]\w+[/\\]" tmp_name = re.search(regex_filter, str(f)).group().strip()[1:-1] out_name = tmp_name.replace("tmp_", "") - f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) + if self.condition_in_output_filename: + f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", f".{out_name}.")) + else: + f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) out_out_files.append(f_out) if meta_splits: # TODO -- GitLab From 113872d033afbf7f1cb6e10d67f91b5f2beaf91a Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 26 May 2023 16:58:23 +0200 Subject: [PATCH 08/36] at least some ISM support --- .../processing/processing.py | 82 ++++++++----------- .../processing_splitting_scaling.py | 47 +++++++---- 2 files changed, 65 insertions(+), 64 deletions(-) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index f7f1b714..b070e36d 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -60,6 +60,7 @@ from ivas_processing_scripts.audiotools.metadata import ( from ivas_processing_scripts.constants import LOGGER_DATEFMT, LOGGER_FORMAT from ivas_processing_scripts.processing.config import TestConfig from ivas_processing_scripts.utils import apply_func_parallel, list_audio, pairwise +from ivas_processing_scripts.audiotools.constants import IVAS_FRAME_LEN_MS class Processing(ABC): @@ -168,7 +169,7 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger): logger.info(f"Splits written to file {cfg.concat_file.with_suffix('.splits.log')}") -def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): +def concat_teardown(x, splits, out_fmt, fs, in_fs, meta, logger: logging.Logger): if not splits: raise ValueError("Splitting not possible without split marker") @@ -186,6 +187,7 @@ def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): split_old = 0 split_signals = [] + split_meta = [] for idx, split in enumerate(splits): # split y = x[split_old:split, :] @@ -196,25 +198,25 @@ def concat_teardown(x, splits, out_fmt, fs, in_fs, logger: logging.Logger): # add signal to list split_signals.append(y) - split_old = split + # split ISM metadata + if out_fmt.startswith("ISM"): + split_meta_object = [] + for obj_meta in meta: + # compute number of frames per split + split_old_frames = int(split_old / IVAS_FRAME_LEN_MS / fs * 1000) + split_frames = int(split / IVAS_FRAME_LEN_MS / fs * 1000) - # split ISM metadata - if out_fmt.startswith("ISM"): # TODO - # for odir in cfg.out_dirs: - # path_input = odir / cfg.items_list[0].name - # out_meta_paths = split_meta_in_file( - # path_input, - # odir, - # cfg.split_names, - # cfg.splits, - # output_format, - # meta_files=cfg.metadata_path[0], - # ) - # out_meta.append(out_meta_paths) - split_meta = repeat(None) - pass - else: - split_meta = repeat(None) + # split + obj_meta = obj_meta[split_old_frames:split_frames, :] + + # add signal to list + split_meta_object.append(obj_meta) + + split_meta.append(split_meta_object) + else: + split_meta = repeat(None) + + split_old = split return split_signals, split_meta @@ -408,47 +410,33 @@ def process_item( copyfile(ppm, out_meta[idx]) -def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, logger): +def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, meta, logger): # remove preamble for ISM metadata - if out_fmt.startswith("ISM"): # TODO - # # search for metadata - # meta_item = metadata_search( - # odir, [Path(item.name)], num_objects=num_channels - # ) - # metadata_array = [] - # for meta_i in meta_item: - # metadata_array.append(np.genfromtxt(meta_i, delimiter=",")) - # - # # cut first half of the metadata - # if cfg.pre2.repeat_signal: - # metadata_array = [m[int(len(m) / 2) :, :] for m in metadata_array] - # - # # remove preamble - # if cfg.pre2.preamble: - # metadata_array = add_remove_preamble( - # metadata_array, cfg.pre2.preamble, add=False - # ) - # - # # write csv files - # write_ISM_metadata_in_file( - # metadata_array, [path_input], automatic_naming=True - # ) - pass + if out_fmt.startswith("ISM"): + # cut first half of the metadata + if repeat_signal: + meta = [m[int(len(m) / 2):, :] for m in meta] + + # remove preamble + if preamble: + meta = add_remove_preamble( + meta, preamble, add=False + ) # remove first half of signal if repeat_signal: if logger: - logger.info("Remove first half of signal") + logger.debug("Remove first half of signal") x = x[int(len(x) / 2):, :] # remove preamble if preamble: if logger: - logger.info("Remove preamble") + logger.debug("Remove preamble") x = trim(x, fs, (preamble, 0)) - return x + return x, meta def preprocess_background_noise(cfg): diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index bc3c977b..c6b8ab8c 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -34,6 +34,7 @@ import logging from pathlib import Path from itertools import repeat import re +import numpy as np from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown from ivas_processing_scripts.audiotools import audio @@ -59,20 +60,25 @@ class Processing_splitting_scaling(Processing): in_file_noerror = Path(f"{in_file.with_suffix('')}.noerror.wav") out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) + # read metadata + meta_arrays = [] + for meta in in_meta: + meta_arrays.append(np.genfromtxt(meta, delimiter=",")) # cut preamble and split file - out_files, file_splits, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, False, logger) + out_files, file_splits, out_meta, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, meta_arrays, False, logger) if self.tx_condition: - out_files_noerror, file_splits_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, True) + in_meta_noerror = None # TODO + out_files_noerror, file_splits_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, in_meta_noerror, True) # scale splitted files if self.loudness: if self.tx_condition: # do special scaling -> measure noerror loudness and apply scaling to signal with error - scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, logger) + scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) file_splits = [f*loud for f, loud in zip(file_splits, scaling_splits)] else: - file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, logger) + file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) # derive output folder names out_out_files = [] @@ -86,7 +92,7 @@ class Processing_splitting_scaling(Processing): f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) out_out_files.append(f_out) if meta_splits: - # TODO + # TODO ISM pass # write file(s) in tmp and output folder @@ -94,13 +100,12 @@ class Processing_splitting_scaling(Processing): write(of, file_s, fs) write(oof, file_s, fs) if meta_s: - pass # TODO + pass # TODO ISM - def revert_preamble_concatenation(self, x, fs, in_file, out_file, noerror=False, logger=None): + def revert_preamble_concatenation(self, x, fs, in_file, out_file, in_meta, noerror=False, logger=None): # remove preamble and first half of signal due to repetition if self.preamble or self.repeat_signal: - # TODO: ISM metadata - x = remove_preamble(x, self.out_fmt, self.fs, self.repeat_signal, self.preamble, logger) + x, in_meta = remove_preamble(x, self.out_fmt, self.fs, self.repeat_signal, self.preamble, in_meta, logger) # reverse concatenation if self.concatenate_input: @@ -112,21 +117,25 @@ class Processing_splitting_scaling(Processing): splits_info_file = Path( f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(in_file.stem).stem)}.splits.log") splits, split_names, split_fs = read_splits_file(splits_info_file) + # split file - file_splits, meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) + file_splits, meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, in_meta, logger) + # set new out_files out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] + out_meta = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] # TODO ISM if self.tx_condition: file_splits_noerror, meta_splits_noerror = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) else: out_files = [out_file] file_splits = [x] - meta_splits = repeat(None) + meta_splits = repeat(None) # TODO + out_meta = repeat(None) # TODO if self.tx_condition: - file_splits_noerror = None + file_splits_noerror = None # TODO meta_splits_noerror = None # TODO - return out_files, file_splits, meta_splits + return out_files, file_splits, out_meta, meta_splits def read_splits_file(splits_file): @@ -138,21 +147,25 @@ def read_splits_file(splits_file): return splits, names, fs -def adjust_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, logger=None): +def adjust_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger=None): scaled_signals = [] - for f in file_splits: + for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) + if isinstance(audio_object, audio.ObjectBasedAudio): + audio_object.object_pos = m scaled_signal, _ = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) scaled_signals.append(scaled_signal) return scaled_signals -def measure_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, logger): +def measure_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger): if logger: logger.debug("Apply special scaling for bitstream error conditions") scaling_splits = [] - for f in file_splits: + for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) + if isinstance(audio_object, audio.ObjectBasedAudio): + audio_object.object_pos = m _, scale_factor = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) scaling_splits.append(scale_factor) return scaling_splits -- GitLab From 25be4451d743f92281509edbf836375c8a728b01 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Tue, 30 May 2023 17:34:43 +0200 Subject: [PATCH 09/36] normal mode works for ISM now --- .../processing_splitting_scaling.py | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index c6b8ab8c..256be014 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -40,6 +40,7 @@ from ivas_processing_scripts.processing.processing import Processing, remove_pre from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import write, read from ivas_processing_scripts.audiotools.wrappers.bs1770 import loudness_norm +from ivas_processing_scripts.audiotools.metadata import write_ISM_metadata_in_file class Processing_splitting_scaling(Processing): @@ -61,21 +62,24 @@ class Processing_splitting_scaling(Processing): out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) # read metadata - meta_arrays = [] - for meta in in_meta: - meta_arrays.append(np.genfromtxt(meta, delimiter=",")) + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + meta_arrays = [] + for meta in in_meta: + meta_arrays.append(np.genfromtxt(meta, delimiter=",")) + else: + meta_arrays = None # cut preamble and split file out_files, file_splits, out_meta, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, meta_arrays, False, logger) if self.tx_condition: in_meta_noerror = None # TODO - out_files_noerror, file_splits_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, in_meta_noerror, True) + out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, in_meta_noerror, True) # scale splitted files if self.loudness: if self.tx_condition: # do special scaling -> measure noerror loudness and apply scaling to signal with error - scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) + scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits_noerror, logger) file_splits = [f*loud for f, loud in zip(file_splits, scaling_splits)] else: file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) @@ -91,16 +95,24 @@ class Processing_splitting_scaling(Processing): else: f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) out_out_files.append(f_out) - if meta_splits: - # TODO ISM - pass + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + out_out_meta = [] + for f in out_out_files: + oom = [] + for idx in range(num_channels): + f_out = f.with_suffix(f".wav.{idx}.csv") + oom.append(f_out) + out_out_meta.append(oom) + else: + out_out_meta = repeat(None) # write file(s) in tmp and output folder - for of, oof, file_s, meta_s in zip(out_files, out_out_files, file_splits, meta_splits): + for of, oof, file_s, om, oom, meta_s in zip(out_files, out_out_files, file_splits, out_meta, out_out_meta, meta_splits): write(of, file_s, fs) write(oof, file_s, fs) - if meta_s: - pass # TODO ISM + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + write_ISM_metadata_in_file(meta_s, om) + write_ISM_metadata_in_file(meta_s, oom) def revert_preamble_concatenation(self, x, fs, in_file, out_file, in_meta, noerror=False, logger=None): # remove preamble and first half of signal due to repetition @@ -123,14 +135,28 @@ class Processing_splitting_scaling(Processing): # set new out_files out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] - out_meta = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] # TODO ISM + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + out_meta = [] + for of in out_files: + of_list = [] + for idx in range(x.shape[1]): + of_list.append(of.with_suffix(f".wav.{idx}.csv")) + out_meta.append(of_list) + else: + out_meta = repeat(None) + if self.tx_condition: file_splits_noerror, meta_splits_noerror = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) else: out_files = [out_file] file_splits = [x] - meta_splits = repeat(None) # TODO - out_meta = repeat(None) # TODO + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + meta_splits = [in_meta] + out_meta = [[out_file.with_suffix(f".wav.{idx}.csv") for idx in range(x.shape[1])]] + else: + meta_splits = repeat(None) + out_meta = repeat(None) + if self.tx_condition: file_splits_noerror = None # TODO meta_splits_noerror = None # TODO -- GitLab From 91fa7589715e42d12cd2dc5c8a5a5c4991b6d948 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Tue, 30 May 2023 19:47:47 +0200 Subject: [PATCH 10/36] fixed some bugs --- .../processing/postprocessing.py | 11 +++-- .../processing/preprocessing_2.py | 4 +- .../processing_splitting_scaling.py | 46 +++++++++++++------ 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/ivas_processing_scripts/processing/postprocessing.py b/ivas_processing_scripts/processing/postprocessing.py index 72e5d2f2..b3bc3f68 100755 --- a/ivas_processing_scripts/processing/postprocessing.py +++ b/ivas_processing_scripts/processing/postprocessing.py @@ -57,9 +57,14 @@ class Postprocessing(Processing): in_file_no_error = Path(f"{in_file.with_suffix('')}.noerror.wav") out_file_no_error = Path(f"{out_file.with_suffix('')}.noerror.wav") if in_meta: - in_meta_no_error = None # TODO + in_meta_noerror = [] + for meta in in_meta: + path_parts = str(meta).split(".") + suffix = ".".join(path_parts[-3:]) + name = ".".join(path_parts[:-3]) + in_meta_noerror.append(Path(f"{name}.noerror.{suffix}")) else: - in_meta_no_error = None + in_meta_noerror = None convert.convert_file( - in_file_no_error, out_file_no_error, logger=logger, in_meta=in_meta_no_error, **self.__dict__ + in_file_no_error, out_file_no_error, logger=logger, in_meta=in_meta_noerror, **self.__dict__ ) diff --git a/ivas_processing_scripts/processing/preprocessing_2.py b/ivas_processing_scripts/processing/preprocessing_2.py index 92068458..2d2fd500 100644 --- a/ivas_processing_scripts/processing/preprocessing_2.py +++ b/ivas_processing_scripts/processing/preprocessing_2.py @@ -73,9 +73,7 @@ class Preprocessing2(Processing): preamble = self.preamble # read out old - metadata = [] - for meta in in_meta: - metadata.append(np.genfromtxt(meta, delimiter=",")) + metadata = audio_object.object_pos # modify metadata metadata = add_remove_preamble(metadata, preamble) diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 256be014..d4ac113a 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -55,13 +55,9 @@ class Processing_splitting_scaling(Processing): # get number of channels from output format num_channels = audio.fromtype(self.out_fmt).num_channels - # read file + + # read file and metadata x, fs = read(in_file, nchannels=num_channels, fs=self.fs) - if self.tx_condition: - in_file_noerror = Path(f"{in_file.with_suffix('')}.noerror.wav") - out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") - x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) - # read metadata if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): meta_arrays = [] for meta in in_meta: @@ -69,11 +65,26 @@ class Processing_splitting_scaling(Processing): else: meta_arrays = None + # read file and metadata for signal with no bitstream errors + if self.tx_condition: + in_file_noerror = Path(f"{in_file.with_suffix('')}.noerror.wav") + out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") + x_noerror, _ = read(in_file_noerror, nchannels=num_channels, fs=self.fs) + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + meta_arrays_noerror = [] + for meta in in_meta: + path_parts = str(meta).split(".") + suffix = ".".join(path_parts[-3:]) + name = ".".join(path_parts[:-3]) + meta_noerror = Path(f"{name}.noerror.{suffix}") + meta_arrays_noerror.append(np.genfromtxt(meta_noerror, delimiter=",")) + else: + meta_arrays_noerror = None + # cut preamble and split file out_files, file_splits, out_meta, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, meta_arrays, False, logger) if self.tx_condition: - in_meta_noerror = None # TODO - out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, in_meta_noerror, True) + out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, meta_arrays_noerror, True, logger=None) # scale splitted files if self.loudness: @@ -82,6 +93,7 @@ class Processing_splitting_scaling(Processing): scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits_noerror, logger) file_splits = [f*loud for f, loud in zip(file_splits, scaling_splits)] else: + # do normal scaling file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) # derive output folder names @@ -113,6 +125,12 @@ class Processing_splitting_scaling(Processing): if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): write_ISM_metadata_in_file(meta_s, om) write_ISM_metadata_in_file(meta_s, oom) + # write noerror files in tmp folder + if self.tx_condition: + for ofne, file_sne, omne, meta_sne in zip(out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror): + write(ofne, file_sne, fs) + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): + write_ISM_metadata_in_file(meta_sne, omne) def revert_preamble_concatenation(self, x, fs, in_file, out_file, in_meta, noerror=False, logger=None): # remove preamble and first half of signal due to repetition @@ -134,7 +152,11 @@ class Processing_splitting_scaling(Processing): file_splits, meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, in_meta, logger) # set new out_files - out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] + if noerror: + out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.noerror.wav") for sn in split_names] + else: + out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] + if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): out_meta = [] for of in out_files: @@ -145,8 +167,6 @@ class Processing_splitting_scaling(Processing): else: out_meta = repeat(None) - if self.tx_condition: - file_splits_noerror, meta_splits_noerror = concat_teardown(x, splits, self.out_fmt, fs, split_fs, logger) else: out_files = [out_file] file_splits = [x] @@ -157,10 +177,6 @@ class Processing_splitting_scaling(Processing): meta_splits = repeat(None) out_meta = repeat(None) - if self.tx_condition: - file_splits_noerror = None # TODO - meta_splits_noerror = None # TODO - return out_files, file_splits, out_meta, meta_splits -- GitLab From 247a4dbe6f759d79f7796fe14e0d867ea1b4fa55 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:27:28 +0200 Subject: [PATCH 11/36] use clone strategy for tests that run a config --- .gitlab-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cbfc7d66..59dc3dc9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -75,6 +75,8 @@ test_audiotools_convert: # run the test configs for the selection experiments experiments: + variables: + GIT_STRATEGY: clone stage: test tags: - linux @@ -85,6 +87,8 @@ experiments: # run some test configs for item creation test_processing: + variables: + GIT_STRATEGY: clone stage: test rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' -- GitLab From e3182c1a57a9019a626f0acaa918260da0b19df2 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:34:12 +0200 Subject: [PATCH 12/36] debug printout for experiments job --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59dc3dc9..ac3d7057 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,10 +79,11 @@ experiments: GIT_STRATEGY: clone stage: test tags: - - linux + - fhg_scripts_runner_2 script: - *print-common-info - *get-codec-binaries + - ls "experiments/selection/P800-1/proc_output" - python3 -m pytest -n auto tests/test_experiments.py # run some test configs for item creation -- GitLab From b37c6190bd12110da5155e27caa038abcd0ad5f0 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:38:05 +0200 Subject: [PATCH 13/36] add debug printout in python code --- ivas_processing_scripts/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index b6378f32..1d17a6b9 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -90,6 +90,7 @@ def main(args): f.resolve().absolute() for f in cfg.output_path.iterdir() ] + print(file_list) if len(file_list) != 0: raise ValueError("Output folder is not empty. Please delete or move files and folders.") -- GitLab From 440efe9ff7c1559a8d55bf3d0b8f2a99cb77d89b Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:48:04 +0200 Subject: [PATCH 14/36] Revert "add debug printout in python code" This reverts commit b37c6190bd12110da5155e27caa038abcd0ad5f0. --- ivas_processing_scripts/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 1d17a6b9..b6378f32 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -90,7 +90,6 @@ def main(args): f.resolve().absolute() for f in cfg.output_path.iterdir() ] - print(file_list) if len(file_list) != 0: raise ValueError("Output folder is not empty. Please delete or move files and folders.") -- GitLab From 72cd4de4355840b7b851b482f41e86c2ba9da679 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:48:15 +0200 Subject: [PATCH 15/36] Revert "debug printout for experiments job" This reverts commit e3182c1a57a9019a626f0acaa918260da0b19df2. --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ac3d7057..59dc3dc9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,11 +79,10 @@ experiments: GIT_STRATEGY: clone stage: test tags: - - fhg_scripts_runner_2 + - linux script: - *print-common-info - *get-codec-binaries - - ls "experiments/selection/P800-1/proc_output" - python3 -m pytest -n auto tests/test_experiments.py # run some test configs for item creation -- GitLab From e3306a79834096a27d91b9d3a67d544dee39d193 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:48:23 +0200 Subject: [PATCH 16/36] Revert "use clone strategy for tests that run a config" This reverts commit 247a4dbe6f759d79f7796fe14e0d867ea1b4fa55. --- .gitlab-ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59dc3dc9..cbfc7d66 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -75,8 +75,6 @@ test_audiotools_convert: # run the test configs for the selection experiments experiments: - variables: - GIT_STRATEGY: clone stage: test tags: - linux @@ -87,8 +85,6 @@ experiments: # run some test configs for item creation test_processing: - variables: - GIT_STRATEGY: clone stage: test rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' -- GitLab From db7c273dd28e26584582d3f3850ab78fc42bd402 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:52:55 +0200 Subject: [PATCH 17/36] ignore hidden files when checking for empty output folder --- ivas_processing_scripts/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index b6378f32..06e42449 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -88,7 +88,7 @@ def main(args): if cfg.output_path.is_dir(): file_list = [ f.resolve().absolute() - for f in cfg.output_path.iterdir() + for f in cfg.output_path.iterdir() if not i.name.startswith(".") ] if len(file_list) != 0: raise ValueError("Output folder is not empty. Please delete or move files and folders.") -- GitLab From 944ecd25abecf24306d43d1979611cf43b7c75a1 Mon Sep 17 00:00:00 2001 From: knj Date: Wed, 31 May 2023 09:58:03 +0200 Subject: [PATCH 18/36] fix variable typo --- ivas_processing_scripts/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 06e42449..0ecb2cdd 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -88,7 +88,7 @@ def main(args): if cfg.output_path.is_dir(): file_list = [ f.resolve().absolute() - for f in cfg.output_path.iterdir() if not i.name.startswith(".") + for f in cfg.output_path.iterdir() if not f.name.startswith(".") ] if len(file_list) != 0: raise ValueError("Output folder is not empty. Please delete or move files and folders.") -- GitLab From 0ac38003d4c404bd90ed5f42d2355a24f66fd121 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Wed, 31 May 2023 10:40:09 +0200 Subject: [PATCH 19/36] changed check of output folder to allow other files and folders --- ivas_processing_scripts/__init__.py | 9 --------- ivas_processing_scripts/utils.py | 11 +++++++---- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ivas_processing_scripts/__init__.py b/ivas_processing_scripts/__init__.py index 0ecb2cdd..80585488 100755 --- a/ivas_processing_scripts/__init__.py +++ b/ivas_processing_scripts/__init__.py @@ -84,15 +84,6 @@ def main(args): # parse configuration cfg = config.TestConfig(args.config) - # check if output folder is empty - if cfg.output_path.is_dir(): - file_list = [ - f.resolve().absolute() - for f in cfg.output_path.iterdir() if not f.name.startswith(".") - ] - if len(file_list) != 0: - raise ValueError("Output folder is not empty. Please delete or move files and folders.") - # set up processing chains chains.init_processing_chains(cfg) diff --git a/ivas_processing_scripts/utils.py b/ivas_processing_scripts/utils.py index 0ce6696e..8671ce90 100755 --- a/ivas_processing_scripts/utils.py +++ b/ivas_processing_scripts/utils.py @@ -52,9 +52,9 @@ Directory/path handling """ -def create_dir(p: str) -> None: +def create_dir(p: str, exist_ok=True) -> None: p = Path(p) - p.mkdir(exist_ok=True, parents=True) + p.mkdir(exist_ok=exist_ok, parents=True) def delete_dir(p: str) -> None: @@ -80,8 +80,11 @@ class DirManager: ) def __enter__(self): - for path in self.create_paths: - create_dir(path) + try: + for path in self.create_paths: + create_dir(path, exist_ok=False) + except FileExistsError: + raise ValueError("At least one of the output folders already exists. Please delete or move this folder.") def __exit__(self, exc_type, exc_value, exc_traceback): for path in self.delete_paths: -- GitLab From 8e6474461a67630760647f300b6c521aafc18a4d Mon Sep 17 00:00:00 2001 From: Treffehn Date: Wed, 31 May 2023 13:25:30 +0200 Subject: [PATCH 20/36] fixed bugs and removed jbm from tests --- .gitignore | 2 +- examples/TEMPLATE.yml | 3 +- ivas_processing_scripts/processing/chains.py | 2 ++ ivas_processing_scripts/processing/evs.py | 3 +- ivas_processing_scripts/processing/ivas.py | 32 +++++++++----------- tests/constants.py | 2 +- tests/data/test_ISM.yml | 2 +- tests/data/test_MC.yml | 12 ++++---- tests/data/test_SBA.yml | 7 +---- 9 files changed, 30 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 3f2d086e..29582b6d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ experiments/selection/*/proc_input/*.wav experiments/selection/*/proc_input/*.pcm experiments/selection/*/proc_output/ *~ -tests/tmp_output_* +tests/temp_output_* tests/cut tests/ref tests/concatenation_folder \ No newline at end of file diff --git a/examples/TEMPLATE.yml b/examples/TEMPLATE.yml index 488c0cb9..80f297a4 100755 --- a/examples/TEMPLATE.yml +++ b/examples/TEMPLATE.yml @@ -25,7 +25,8 @@ ### Any relative paths will be interpreted relative to the working directory the script is called from! ### Usage of absolute paths is recommended. ### Do not use file names with dots "." in them! This is not supported, use "_" instead -### For Windows user: please use double back slash '\\' in paths and add '.exe' to executable definitions +### Do not use "tmp_" in file or folder names ("temp_" is fine) +### For Windows user: please use double back slash '\\' in paths ### REQUIRED: Input path or file input_path: ".../ivas/items/HOA3" ### REQUIRED: Output path or file diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 68594d9e..cbdec29b 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -245,6 +245,7 @@ def get_processing_chain( "in_fmt": tmp_in_fmt, "out_fmt": "MONO", "multiprocessing": cfg.multiprocessing, + "tx_condition": False, }, name="mono_dmx", ) @@ -338,6 +339,7 @@ def get_processing_chain( "in_fmt": tmp_in_fmt, "out_fs": tmp_in_fs, "out_fmt": cond_cfg.get("sba_fmt"), + "tx_condition": False, }, name="sba_fmt_rend", ) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 039dc5a6..1a7d7838 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -36,7 +36,7 @@ import platform from itertools import repeat from pathlib import Path from shutil import copyfile -from typing import Optional, Union +from typing import Optional, Union, Tuple from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import ( @@ -234,6 +234,7 @@ class EVS(Processing): ) # run all decoders twice with and without bitstream errors + # TODO: voip mode only for processed bitstreams for jbm logger.debug(f"Running EVS decoders for {out_file.stem.split('.')[0]}") apply_func_parallel( self.dec, diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index 7db4f2e1..cd50f24f 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -34,7 +34,7 @@ import logging import os.path import platform from pathlib import Path -from typing import Optional, Union +from typing import Optional, Union, Tuple from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import parse_wave_header, read @@ -127,13 +127,13 @@ class IVAS(Processing): # apply bitstream processing and save unprocessed bitstream bitstream_noerror = bitstream - bitstream = self.simulate_tx(in_file, bitstream, logger) + bitstream, voip = self.simulate_tx(in_file, bitstream, logger) # decode twice with and without bitstream errors - self.dec(bitstream, out_file, logger) + self.dec(bitstream, out_file, voip=voip, logger=logger) if bitstream_noerror != bitstream and self.tx_condition: out_file_unprocessed = Path(f"{out_file.parent.joinpath(out_file.stem)}.noerror{out_file.suffix}") - self.dec(bitstream_noerror, out_file_unprocessed, logger) + self.dec(bitstream_noerror, out_file_unprocessed, voip=False, logger=logger) def enc( self, @@ -222,7 +222,7 @@ class IVAS(Processing): in_file: Union[Path, str], bitstream: Path, logger: Optional[logging.Logger] = None, - ) -> Union[Path, str]: + ) -> Tuple[Union[Path, str], bool]: if self.tx is not None: if self.tx["type"] == "JBM": bs, ext = os.path.splitext(bitstream) @@ -236,15 +236,8 @@ class IVAS(Processing): self.tx["n_frames_per_packet"], logger=logger, ) - # add -voip cmdline option to the decoder - # TODO: tracefile also? - if self.dec_opts: - if "-voip" not in self.dec_opts: - self.dec_opts.extend(["-voip"]) - - else: - self.dec_opts = ["-voip"] - return bitstream_processed + voip = True + return bitstream_processed, voip elif self.tx["type"] == "FER": bs, ext = os.path.splitext(bitstream) @@ -270,13 +263,13 @@ class IVAS(Processing): master_seed=self.tx["master_seed"], prerun_seed=self.tx["prerun_seed"], ) - - return bitstream_processed + voip = False + return bitstream_processed, voip else: - return bitstream + return bitstream, False def dec( - self, bitstream: Path, out_file: Path, logger: Optional[logging.Logger] = None + self, bitstream: Path, out_file: Path, voip=False, logger: Optional[logging.Logger] = None ) -> None: logger.debug(f"IVAS decoder {bitstream} -> {out_file}") @@ -287,6 +280,9 @@ class IVAS(Processing): if hasattr(self, "trajectory"): cmd.extend(["-T", self.trajectory]) + # add -voip cmdline option to the decoder + if voip: + cmd.extend(["-voip"]) if self.dec_opts: cmd.extend(self.dec_opts) diff --git a/tests/constants.py b/tests/constants.py index fb91b23c..f877a5a8 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -197,7 +197,7 @@ HR_TRAJECTORIES_TO_TEST = [ """ Generate Test Items Configs """ INPUT_CONFIG_FILES = [ str(TEST_VECTOR_DIR.joinpath("test_ISM.yml")), - # str(TEST_VECTOR_DIR.joinpath("test_MASA.yml")), # TODO + # str(TEST_VECTOR_DIR.joinpath("test_MASA.yml")), str(TEST_VECTOR_DIR.joinpath("test_MC.yml")), str(TEST_VECTOR_DIR.joinpath("test_SBA.yml")), ] diff --git a/tests/data/test_ISM.yml b/tests/data/test_ISM.yml index 7122ab4e..f458c44e 100644 --- a/tests/data/test_ISM.yml +++ b/tests/data/test_ISM.yml @@ -24,7 +24,7 @@ ### REQUIRED: Input path or file input_path: "./tests/concatenation_folder/ISM" ### REQUIRED: Output path or file -output_path: "./tests/tmp_output_ISM" +output_path: "./tests/temp_output_ISM" ### Metadata path or file(s) ### If input format is ISM{1-4} a path for the metadata files can be specified; ### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherise ignored) diff --git a/tests/data/test_MC.yml b/tests/data/test_MC.yml index 9e2c748e..4e1ea6f1 100644 --- a/tests/data/test_MC.yml +++ b/tests/data/test_MC.yml @@ -24,7 +24,7 @@ master_seed: 5 ### REQUIRED: Input path or file input_path: "./tests/concatenation_folder/MC" ### REQUIRED: Output path or file -output_path: "./tests/tmp_output_MC" +output_path: "./tests/temp_output_MC" ### Metadata path or file(s) ### If input format is ISM{1-4} a path for the metadata files can be specified; ### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherise ignored) @@ -119,25 +119,25 @@ preprocessing_2: ### can be given globally here or in individual conditions of type ivas or evs tx: ### REQUIRED: Type of bitstream processing; possible types: "JBM" or "FER" - type: "JBM" + type: "FER" ### JBM ### REQUIRED: either error_pattern or error_profile ### delay error profile file # error_pattern: ".../dly_error_profile.dat" ### Index of one of the existing delay error profile files to use (1-11) - error_profile: 5 + #error_profile: 5 ## nFramesPerPacket parameter for the network simulator; default = 1 - n_frames_per_packet: 2 + #n_frames_per_packet: 2 ### FER ### REQUIRED: either error_pattern or error_rate ### Frame error pattern file # error_pattern: "path/pattern.192" ### Error rate in percent - # error_rate: 5 + error_rate: 5 ### Additional seed to specify number of preruns; default = 0 - # prerun_seed: 2 + prerun_seed: 2 ################################################ ### Configuration for conditions under test diff --git a/tests/data/test_SBA.yml b/tests/data/test_SBA.yml index da6bfe22..9bd98804 100644 --- a/tests/data/test_SBA.yml +++ b/tests/data/test_SBA.yml @@ -24,7 +24,7 @@ master_seed: 5 ### REQUIRED: Input path or file input_path: "./tests/concatenation_folder/SBA" ### REQUIRED: Output path or file -output_path: "./tests/tmp_output_SBA" +output_path: "./tests/temp_output_SBA" ### Metadata path or file(s) ### If input format is ISM{1-4} a path for the metadata files can be specified; ### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherise ignored) @@ -260,11 +260,6 @@ conditions_to_generate: #bin: EVS_dec ### Decoder output sampling rate; default = null (same as input) # fs: 48000 - ### Bitstream options - tx: - ### For possible arguments see overall bitstream modification - type: "JBM" - error_profile: 3 sba_fmt: "PLANARFOA" ################################################ -- GitLab From 5ae85e5222e833ee2396ff8dd7d3ada6b8871473 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 12:49:22 +0200 Subject: [PATCH 21/36] mostly formatting --- examples/TEMPLATE.yml | 2 +- ivas_processing_scripts/processing/chains.py | 4 +- ivas_processing_scripts/processing/evs.py | 17 +- ivas_processing_scripts/processing/ivas.py | 12 +- .../processing/postprocessing.py | 6 +- .../processing/processing.py | 33 +--- .../processing_splitting_scaling.py | 159 ++++++++++++++---- ivas_processing_scripts/utils.py | 4 +- tests/data/test_ISM.yml | 5 +- 9 files changed, 166 insertions(+), 76 deletions(-) diff --git a/examples/TEMPLATE.yml b/examples/TEMPLATE.yml index 80f297a4..5b50ace6 100755 --- a/examples/TEMPLATE.yml +++ b/examples/TEMPLATE.yml @@ -30,7 +30,7 @@ ### REQUIRED: Input path or file input_path: ".../ivas/items/HOA3" ### REQUIRED: Output path or file -output_path: ".../tmp_output" +output_path: ".../temp_output" ### Metadata path or file(s) ### If input format is ISM{1-4} a path for the metadata files can be specified; ### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherise ignored) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index cbdec29b..7565b142 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -39,7 +39,9 @@ from ivas_processing_scripts.processing.ivas import IVAS, validate_sba_fmt from ivas_processing_scripts.processing.postprocessing import Postprocessing from ivas_processing_scripts.processing.preprocessing import Preprocessing from ivas_processing_scripts.processing.preprocessing_2 import Preprocessing2 -from ivas_processing_scripts.processing.processing_splitting_scaling import Processing_splitting_scaling +from ivas_processing_scripts.processing.processing_splitting_scaling import ( + Processing_splitting_scaling, +) from ivas_processing_scripts.utils import get_abs_path, list_audio diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 1a7d7838..6cf564a9 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -36,7 +36,7 @@ import platform from itertools import repeat from pathlib import Path from shutil import copyfile -from typing import Optional, Union, Tuple +from typing import Optional, Tuple, Union from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import ( @@ -205,7 +205,9 @@ class EVS(Processing): # run processing split_chan_bs = [f.with_suffix(".192") for f in split_chan_files] split_chan_out = [f.with_suffix(".pcm") for f in split_chan_files] - split_chan_out_noerror = [f.with_suffix(".noerror.pcm") for f in split_chan_files] + split_chan_out_noerror = [ + f.with_suffix(".noerror.pcm") for f in split_chan_files + ] # run all encoders logger.debug(f"Running EVS encoders for {out_file.stem.split('.')[0]}") @@ -257,7 +259,12 @@ class EVS(Processing): combine(split_chan_out, out_file, in_fs=self.out_fs, is_planar=is_planar) if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: out_file_unprocessed = f"{Path(out_file.parent).joinpath(Path(out_file.name).with_suffix(''))}.noerror{out_file.suffix}" - combine(split_chan_out_noerror, out_file_unprocessed, in_fs=self.out_fs, is_planar=is_planar) + combine( + split_chan_out_noerror, + out_file_unprocessed, + in_fs=self.out_fs, + is_planar=is_planar, + ) # copy ISM metadata for ISM pass-through if in_meta: for idx in range(len(in_meta)): @@ -268,8 +275,8 @@ class EVS(Processing): copyfile(in_meta[idx], out_file_meta) if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: out_file_meta_unprocessed = ( - out_file.parent - / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" + out_file.parent + / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" ) copyfile(in_meta[idx], out_file_meta_unprocessed) diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index cd50f24f..94a1f513 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -34,7 +34,7 @@ import logging import os.path import platform from pathlib import Path -from typing import Optional, Union, Tuple +from typing import Optional, Tuple, Union from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audiofile import parse_wave_header, read @@ -132,7 +132,9 @@ class IVAS(Processing): # decode twice with and without bitstream errors self.dec(bitstream, out_file, voip=voip, logger=logger) if bitstream_noerror != bitstream and self.tx_condition: - out_file_unprocessed = Path(f"{out_file.parent.joinpath(out_file.stem)}.noerror{out_file.suffix}") + out_file_unprocessed = Path( + f"{out_file.parent.joinpath(out_file.stem)}.noerror{out_file.suffix}" + ) self.dec(bitstream_noerror, out_file_unprocessed, voip=False, logger=logger) def enc( @@ -269,7 +271,11 @@ class IVAS(Processing): return bitstream, False def dec( - self, bitstream: Path, out_file: Path, voip=False, logger: Optional[logging.Logger] = None + self, + bitstream: Path, + out_file: Path, + voip=False, + logger: Optional[logging.Logger] = None, ) -> None: logger.debug(f"IVAS decoder {bitstream} -> {out_file}") diff --git a/ivas_processing_scripts/processing/postprocessing.py b/ivas_processing_scripts/processing/postprocessing.py index b3bc3f68..4fc1ccdc 100755 --- a/ivas_processing_scripts/processing/postprocessing.py +++ b/ivas_processing_scripts/processing/postprocessing.py @@ -66,5 +66,9 @@ class Postprocessing(Processing): else: in_meta_noerror = None convert.convert_file( - in_file_no_error, out_file_no_error, logger=logger, in_meta=in_meta_noerror, **self.__dict__ + in_file_no_error, + out_file_no_error, + logger=logger, + in_meta=in_meta_noerror, + **self.__dict__, ) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index b070e36d..25e82c68 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -42,13 +42,9 @@ from warnings import warn import numpy as np from ivas_processing_scripts.audiotools import audio -from ivas_processing_scripts.audiotools.audiofile import ( - concat, - read, - trim, - write, -) from ivas_processing_scripts.audiotools.audioarray import window +from ivas_processing_scripts.audiotools.audiofile import concat, read, trim, write +from ivas_processing_scripts.audiotools.constants import IVAS_FRAME_LEN_MS from ivas_processing_scripts.audiotools.convert.__init__ import convert from ivas_processing_scripts.audiotools.metadata import ( add_remove_preamble, @@ -60,7 +56,6 @@ from ivas_processing_scripts.audiotools.metadata import ( from ivas_processing_scripts.constants import LOGGER_DATEFMT, LOGGER_FORMAT from ivas_processing_scripts.processing.config import TestConfig from ivas_processing_scripts.utils import apply_func_parallel, list_audio, pairwise -from ivas_processing_scripts.audiotools.constants import IVAS_FRAME_LEN_MS class Processing(ABC): @@ -386,12 +381,6 @@ def process_item( fh.setFormatter(logging.Formatter(LOGGER_FORMAT, datefmt=LOGGER_DATEFMT)) item_logger.addHandler(fh) - # set info about tx and loudness - try: - tx_condition = p.tx_condition - except AttributeError: - tx_condition = False - p.process(input, output, input_meta, item_logger) # copy output and metadata from final process to output file @@ -400,14 +389,6 @@ def process_item( if processing_paths_meta[-1]: for idx, ppm in enumerate(processing_paths_meta[-1]): copyfile(ppm, out_meta[idx]) - # if bitstream processing and loudness adjustment copy additional file - if tx_condition: - out_file_noerror = Path(f"{out_file.with_suffix('')}.noerror.wav") - in_file_noerror = Path(f"{processing_paths[-1].with_suffix('')}.noerror.wav") - copyfile(in_file_noerror, out_file_noerror) - if processing_paths_meta[-1]: # TODO - for idx, ppm in enumerate(processing_paths_meta[-1]): - copyfile(ppm, out_meta[idx]) def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, meta, logger): @@ -416,19 +397,17 @@ def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, meta, logger): if out_fmt.startswith("ISM"): # cut first half of the metadata if repeat_signal: - meta = [m[int(len(m) / 2):, :] for m in meta] + meta = [m[int(len(m) / 2) :, :] for m in meta] # remove preamble if preamble: - meta = add_remove_preamble( - meta, preamble, add=False - ) + meta = add_remove_preamble(meta, preamble, add=False) # remove first half of signal if repeat_signal: if logger: logger.debug("Remove first half of signal") - x = x[int(len(x) / 2):, :] + x = x[int(len(x) / 2) :, :] # remove preamble if preamble: @@ -519,5 +498,3 @@ def multiple_of_frame_size( warn( f"The length ({n_samples_x} samples) of audio ({item.name}) is not a multiple of frame length (20 ms)." ) - - diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index d4ac113a..5a069625 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -1,5 +1,22 @@ #!/usr/bin/env python3 import copy +import logging +import re +from itertools import repeat +from pathlib import Path + +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.metadata import write_ISM_metadata_in_file +from ivas_processing_scripts.audiotools.wrappers.bs1770 import loudness_norm +from ivas_processing_scripts.processing.processing import ( + Processing, + concat_teardown, + remove_preamble, +) + # # (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., @@ -30,18 +47,6 @@ import copy # the United Nations Convention on Contracts on the International Sales of Goods. # -import logging -from pathlib import Path -from itertools import repeat -import re -import numpy as np - -from ivas_processing_scripts.processing.processing import Processing, remove_preamble, concat_teardown -from ivas_processing_scripts.audiotools import audio -from ivas_processing_scripts.audiotools.audiofile import write, read -from ivas_processing_scripts.audiotools.wrappers.bs1770 import loudness_norm -from ivas_processing_scripts.audiotools.metadata import write_ISM_metadata_in_file - class Processing_splitting_scaling(Processing): def __init__(self, attrs: dict): @@ -77,24 +82,62 @@ class Processing_splitting_scaling(Processing): suffix = ".".join(path_parts[-3:]) name = ".".join(path_parts[:-3]) meta_noerror = Path(f"{name}.noerror.{suffix}") - meta_arrays_noerror.append(np.genfromtxt(meta_noerror, delimiter=",")) + meta_arrays_noerror.append( + np.genfromtxt(meta_noerror, delimiter=",") + ) else: meta_arrays_noerror = None # cut preamble and split file - out_files, file_splits, out_meta, meta_splits = self.revert_preamble_concatenation(x, fs, in_file, out_file, meta_arrays, False, logger) + ( + out_files, + file_splits, + out_meta, + meta_splits, + ) = self.revert_preamble_concatenation( + x, fs, in_file, out_file, meta_arrays, False, logger + ) if self.tx_condition: - out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror = self.revert_preamble_concatenation(x_noerror, fs, in_file_noerror, out_file_noerror, meta_arrays_noerror, True, logger=None) + ( + out_files_noerror, + file_splits_noerror, + out_meta_noerror, + meta_splits_noerror, + ) = self.revert_preamble_concatenation( + x_noerror, + fs, + in_file_noerror, + out_file_noerror, + meta_arrays_noerror, + True, + logger=None, + ) # scale splitted files if self.loudness: if self.tx_condition: # do special scaling -> measure noerror loudness and apply scaling to signal with error - scaling_splits = measure_loudness(file_splits_noerror, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits_noerror, logger) - file_splits = [f*loud for f, loud in zip(file_splits, scaling_splits)] + scaling_splits = measure_loudness( + file_splits_noerror, + self.out_fmt, + fs, + self.loudness, + self.loudness_fmt, + meta_splits_noerror, + logger, + ) + file_splits = [f * loud for f, loud in zip(file_splits, scaling_splits)] else: # do normal scaling - file_splits = adjust_loudness(file_splits, self.out_fmt, fs, self.loudness, self.loudness_fmt, meta_splits, logger) + file_splits = adjust_loudness( + file_splits, + self.out_fmt, + fs, + self.loudness, + self.loudness_fmt, + meta_splits, + logger, + ) # derive output folder names out_out_files = [] @@ -103,9 +146,17 @@ class Processing_splitting_scaling(Processing): tmp_name = re.search(regex_filter, str(f)).group().strip()[1:-1] out_name = tmp_name.replace("tmp_", "") if self.condition_in_output_filename: - f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", f".{out_name}.")) + f_out = Path( + str(f) + .replace(tmp_name, out_name) + .replace(".processing_splitting_scaling.", f".{out_name}.") + ) else: - f_out = Path(str(f).replace(tmp_name, out_name).replace(".processing_splitting_scaling.", ".")) + f_out = Path( + str(f) + .replace(tmp_name, out_name) + .replace(".processing_splitting_scaling.", ".") + ) out_out_files.append(f_out) if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): out_out_meta = [] @@ -119,7 +170,9 @@ class Processing_splitting_scaling(Processing): out_out_meta = repeat(None) # write file(s) in tmp and output folder - for of, oof, file_s, om, oom, meta_s in zip(out_files, out_out_files, file_splits, out_meta, out_out_meta, meta_splits): + for of, oof, file_s, om, oom, meta_s in zip( + out_files, out_out_files, file_splits, out_meta, out_out_meta, meta_splits + ): write(of, file_s, fs) write(oof, file_s, fs) if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): @@ -127,35 +180,60 @@ class Processing_splitting_scaling(Processing): write_ISM_metadata_in_file(meta_s, oom) # write noerror files in tmp folder if self.tx_condition: - for ofne, file_sne, omne, meta_sne in zip(out_files_noerror, file_splits_noerror, out_meta_noerror, meta_splits_noerror): + for ofne, file_sne, omne, meta_sne in zip( + out_files_noerror, + file_splits_noerror, + out_meta_noerror, + meta_splits_noerror, + ): write(ofne, file_sne, fs) if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): write_ISM_metadata_in_file(meta_sne, omne) - def revert_preamble_concatenation(self, x, fs, in_file, out_file, in_meta, noerror=False, logger=None): + def revert_preamble_concatenation( + self, x, fs, in_file, out_file, in_meta, noerror=False, logger=None + ): # remove preamble and first half of signal due to repetition if self.preamble or self.repeat_signal: - x, in_meta = remove_preamble(x, self.out_fmt, self.fs, self.repeat_signal, self.preamble, in_meta, logger) + x, in_meta = remove_preamble( + x, + self.out_fmt, + self.fs, + self.repeat_signal, + self.preamble, + in_meta, + logger, + ) # reverse concatenation if self.concatenate_input: # read out splits file -> start/end, names, sampling rate if noerror: splits_info_file = Path( - f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(Path(in_file.stem).stem).stem)}.splits.log") + f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(Path(in_file.stem).stem).stem)}.splits.log" + ) else: splits_info_file = Path( - f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(in_file.stem).stem)}.splits.log") + f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(in_file.stem).stem)}.splits.log" + ) splits, split_names, split_fs = read_splits_file(splits_info_file) # split file - file_splits, meta_splits = concat_teardown(x, splits, self.out_fmt, fs, split_fs, in_meta, logger) + file_splits, meta_splits = concat_teardown( + x, splits, self.out_fmt, fs, split_fs, in_meta, logger + ) # set new out_files if noerror: - out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.noerror.wav") for sn in split_names] + out_files = [ + in_file.parent.joinpath(sn).with_suffix(f".{self.name}.noerror.wav") + for sn in split_names + ] else: - out_files = [in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") for sn in split_names] + out_files = [ + in_file.parent.joinpath(sn).with_suffix(f".{self.name}.wav") + for sn in split_names + ] if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): out_meta = [] @@ -172,7 +250,12 @@ class Processing_splitting_scaling(Processing): file_splits = [x] if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): meta_splits = [in_meta] - out_meta = [[out_file.with_suffix(f".wav.{idx}.csv") for idx in range(x.shape[1])]] + out_meta = [ + [ + out_file.with_suffix(f".wav.{idx}.csv") + for idx in range(x.shape[1]) + ] + ] else: meta_splits = repeat(None) out_meta = repeat(None) @@ -189,25 +272,33 @@ def read_splits_file(splits_file): return splits, names, fs -def adjust_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger=None): +def adjust_loudness( + file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger=None +): scaled_signals = [] for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) if isinstance(audio_object, audio.ObjectBasedAudio): audio_object.object_pos = m - scaled_signal, _ = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) + scaled_signal, _ = loudness_norm( + audio_object, loudness, loudness_fmt, logger=logger + ) scaled_signals.append(scaled_signal) return scaled_signals def measure_loudness(file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger): if logger: - logger.debug("Apply special scaling for bitstream error conditions") + logger.debug( + "Apply special scaling for bitstream error conditions. The following values are based on the signal without error" + ) scaling_splits = [] for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) if isinstance(audio_object, audio.ObjectBasedAudio): audio_object.object_pos = m - _, scale_factor = loudness_norm(audio_object, loudness, loudness_fmt, logger=logger) + _, scale_factor = loudness_norm( + audio_object, loudness, loudness_fmt, logger=logger + ) scaling_splits.append(scale_factor) return scaling_splits diff --git a/ivas_processing_scripts/utils.py b/ivas_processing_scripts/utils.py index 8671ce90..b46a104e 100755 --- a/ivas_processing_scripts/utils.py +++ b/ivas_processing_scripts/utils.py @@ -84,7 +84,9 @@ class DirManager: for path in self.create_paths: create_dir(path, exist_ok=False) except FileExistsError: - raise ValueError("At least one of the output folders already exists. Please delete or move this folder.") + raise ValueError( + "At least one of the output folders already exists. Please delete or move this folder." + ) def __exit__(self, exc_type, exc_value, exc_traceback): for path in self.delete_paths: diff --git a/tests/data/test_ISM.yml b/tests/data/test_ISM.yml index f458c44e..9f1fe799 100644 --- a/tests/data/test_ISM.yml +++ b/tests/data/test_ISM.yml @@ -51,6 +51,7 @@ metadata_path: ### searches for the specified substring in found filenames; default = null # input_select: # - "48kHz" +condition_in_output_filename: true ################################################ ### Input configuration @@ -70,11 +71,11 @@ 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" + mask: "HP50" ### Target sampling rate in Hz for resampling; default = null (no resampling) fs: 48000 ### Target loudness in LKFS; default = null (no loudness change applied) - loudness: -26 + loudness: -30 ### Spatial audio format in which loudness is adjusted (only used if preprocessing loudness is not null); ### default = null (uses preprocessing fmt if possible) # loudness_fmt: "BINAURAL" -- GitLab From cc3bb913db12c22e8679dc700c6107b3d8e451fa Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 13:32:18 +0200 Subject: [PATCH 22/36] JBM EVS special loudness scaling implemented --- ivas_processing_scripts/processing/evs.py | 34 +++++++++++-------- ivas_processing_scripts/processing/ivas.py | 2 +- .../processing_splitting_scaling.py | 2 ++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 6cf564a9..b2d736f9 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -234,13 +234,14 @@ class EVS(Processing): "mt" if self.multiprocessing else None, show_progress=False, ) + voip = [scb[1] for scb in split_chan_bs] + split_chan_bs = [scb[0] for scb in split_chan_bs] # run all decoders twice with and without bitstream errors - # TODO: voip mode only for processed bitstreams for jbm logger.debug(f"Running EVS decoders for {out_file.stem.split('.')[0]}") apply_func_parallel( self.dec, - zip(split_chan_bs, split_chan_out, repeat(logger)), + zip(split_chan_bs, split_chan_out, voip, repeat(logger)), None, "mt" if self.multiprocessing else None, show_progress=False, @@ -248,7 +249,7 @@ class EVS(Processing): if split_chan_bs_unprocessed != split_chan_bs: apply_func_parallel( self.dec, - zip(split_chan_bs_unprocessed, split_chan_out_noerror, repeat(logger)), + zip(split_chan_bs_unprocessed, split_chan_out_noerror, repeat(False), repeat(logger)), None, "mt" if self.multiprocessing else None, show_progress=False, @@ -362,7 +363,7 @@ class EVS(Processing): in_file: Union[Path, str], bitstream: Path, logger: Optional[logging.Logger] = None, - ) -> Union[Path, str]: + ) -> Tuple[Union[Path, str], bool]: if self.tx is not None: if self.tx["type"] == "JBM": bs, ext = os.path.splitext(bitstream) @@ -375,14 +376,8 @@ class EVS(Processing): self.tx["error_profile"], self.tx["n_frames_per_packet"], ) - # add -voip cmdline option to the decoder - # TODO: tracefile also? - if self.dec_opts: - if "-voip" not in self.dec_opts: - self.dec_opts.extend(["-voip"]) - else: - self.dec_opts = ["-voip"] - return bitstream_processed + voip = True + return bitstream_processed, voip elif self.tx["type"] == "FER": bs, ext = os.path.splitext(bitstream) @@ -406,21 +401,30 @@ class EVS(Processing): master_seed=self.tx["master_seed"], prerun_seed=self.tx["prerun_seed"], ) - - return bitstream_processed + voip = False + return bitstream_processed, voip else: - return bitstream + voip = False + return bitstream, voip def dec( self, bitstream: Path, out_pcm_file: Path, + voip: bool = False, logger: Optional[logging.Logger] = None, ) -> None: cmd = [self.dec_bin] if self._use_wine: cmd.insert(0, "wine") + # add -voip cmdline option to the decoder + if voip: + cmd.extend(["-voip"]) + + if self.dec_opts: + cmd.extend(self.dec_opts) + if self.dec_opts: cmd.extend(self.dec_opts) diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index 94a1f513..b194b7a7 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -274,7 +274,7 @@ class IVAS(Processing): self, bitstream: Path, out_file: Path, - voip=False, + voip: bool = False, logger: Optional[logging.Logger] = None, ) -> None: logger.debug(f"IVAS decoder {bitstream} -> {out_file}") diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 5a069625..4ceb5370 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -275,6 +275,8 @@ def read_splits_file(splits_file): def adjust_loudness( file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger=None ): + if logger: + logger.debug("Apply normal loudness scaling. The following loudness values are in the concatenation order.") scaled_signals = [] for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) -- GitLab From f2872b639062dc71c6b016943131e6ca2852df89 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 14:51:56 +0200 Subject: [PATCH 23/36] fixed some merge problems --- ivas_processing_scripts/processing/chains.py | 2 +- ivas_processing_scripts/processing/evs.py | 14 +++++++------- .../processing/postprocessing.py | 1 + ivas_processing_scripts/processing/processing.py | 7 ------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index bcaef860..c69d6013 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -490,7 +490,7 @@ def get_processing_chain( { "fs": post_cfg["fs"], "in_fmt": post_cfg["fmt"], - "out_fmt": post_cfg["fmt"], # no rendering here + "out_fmt": post_fmt, # no rendering here "concatenate_input": pre2_cfg.get("concatenate_input", False), "preamble": pre2_cfg.get("preamble", 0), "repeat_signal": pre2_cfg.get("repeat_signal", False), diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 2a69b0b7..34719415 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -257,7 +257,7 @@ class EVS(Processing): is_planar=is_planar, ) # copy ISM metadata for ISM pass-through - if in_meta: + if isinstance(self.in_fmt, audio.ObjectBasedAudio): for idx in range(len(in_meta)): out_file_meta = ( out_file.parent @@ -277,12 +277,12 @@ class EVS(Processing): md_file_out = out_file.parent / (out_file.name + ".met") copyfile(md_file_in, md_file_out) # TODO: add next part for MASA - #if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: - # out_file_meta_unprocessed = ( - #out_file.parent - #/ f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" - #) - # copyfile(in_meta[idx], out_file_meta_unprocessed) + if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: + out_file_meta_unprocessed = ( + out_file.parent + / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" + ) + copyfile(in_meta[idx], out_file_meta_unprocessed) elif out_file.suffix == ".txt": raise NotImplementedError(".txt file support is WIP") diff --git a/ivas_processing_scripts/processing/postprocessing.py b/ivas_processing_scripts/processing/postprocessing.py index 4fc1ccdc..50c2d745 100755 --- a/ivas_processing_scripts/processing/postprocessing.py +++ b/ivas_processing_scripts/processing/postprocessing.py @@ -56,6 +56,7 @@ class Postprocessing(Processing): if self.tx_condition: in_file_no_error = Path(f"{in_file.with_suffix('')}.noerror.wav") out_file_no_error = Path(f"{out_file.with_suffix('')}.noerror.wav") + # TODO: also copy MASA metadata if in_meta: in_meta_noerror = [] for meta in in_meta: diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index e669a2d6..fef1e7a2 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -169,13 +169,6 @@ def concat_teardown(x, splits, out_fmt, fs, in_fs, meta, logger: logging.Logger) if not splits: raise ValueError("Splitting not possible without split marker") - output_format = cfg.postprocessing["fmt"] - if isinstance(output_format, list): - output_format = output_format[-1] - - out_files = [] - out_meta = [] - if logger: logger.debug("Split files") -- GitLab From 8cc8420d4a585fe58c28e2ba230d786f54e881c1 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 16:30:14 +0200 Subject: [PATCH 24/36] added tx_condition to postprocessing call --- ivas_processing_scripts/processing/chains.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index c69d6013..542176e2 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -247,6 +247,7 @@ def get_processing_chain( elif cond_cfg["type"] == "esdru": tmp_esdru_alpha = cond_cfg["alpha"] elif cond_cfg["type"] == "mono_dmx": + # add another postprocessing from in_fmt to mono chain["processes"].append( Postprocessing( { @@ -260,7 +261,6 @@ def get_processing_chain( ) ) tmp_in_fmt = "MONO" - # add another postprocessing from in_fmt to mono elif cond_cfg["type"] == "evs": cod_cfg = cond_cfg["cod"] dec_cfg = cond_cfg["dec"] @@ -460,6 +460,7 @@ def get_processing_chain( "in_fmt": fmt_in, "out_fs": tmp_in_fs, "out_fmt": fmt_out, + "tx_condition": tx_condition, } ) ) -- GitLab From 2ab5217df2ae21e7e877f9a3adc9f740fd2657a0 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 16:57:58 +0200 Subject: [PATCH 25/36] added names to postprocessing steps to debug outputs --- ivas_processing_scripts/processing/chains.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 542176e2..474922fb 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -321,7 +321,8 @@ def get_processing_chain( "out_fmt": cod_fmt, "multiprocessing": cfg.multiprocessing, "tx_condition": False, - } + }, + name="cod_fmt", ) ) tmp_in_fmt = cod_fmt @@ -412,7 +413,8 @@ def get_processing_chain( "out_fmt": cod_fmt, "multiprocessing": cfg.multiprocessing, "tx_condition": False, - } + }, + name="cod_fmt", ) ) tmp_in_fmt = cod_fmt @@ -461,7 +463,8 @@ def get_processing_chain( "out_fs": tmp_in_fs, "out_fmt": fmt_out, "tx_condition": tx_condition, - } + }, + name=f"post_{fmt_out}", ) ) tmp_in_fmt = fmt_out -- GitLab From cfec4daf4feff09349db56838bbd44de02e81f9f Mon Sep 17 00:00:00 2001 From: Treffehn Date: Thu, 1 Jun 2023 17:20:32 +0200 Subject: [PATCH 26/36] only small changes --- ivas_processing_scripts/processing/postprocessing.py | 2 +- .../processing/processing_splitting_scaling.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ivas_processing_scripts/processing/postprocessing.py b/ivas_processing_scripts/processing/postprocessing.py index 50c2d745..b96d6b5c 100755 --- a/ivas_processing_scripts/processing/postprocessing.py +++ b/ivas_processing_scripts/processing/postprocessing.py @@ -56,7 +56,7 @@ class Postprocessing(Processing): if self.tx_condition: in_file_no_error = Path(f"{in_file.with_suffix('')}.noerror.wav") out_file_no_error = Path(f"{out_file.with_suffix('')}.noerror.wav") - # TODO: also copy MASA metadata + if in_meta: in_meta_noerror = [] for meta in in_meta: diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 4ceb5370..03b7cfb6 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -149,13 +149,13 @@ class Processing_splitting_scaling(Processing): f_out = Path( str(f) .replace(tmp_name, out_name) - .replace(".processing_splitting_scaling.", f".{out_name}.") + .replace(f".{self.name}.", f".{out_name}.") ) else: f_out = Path( str(f) .replace(tmp_name, out_name) - .replace(".processing_splitting_scaling.", ".") + .replace(f".{self.name}.", ".") ) out_out_files.append(f_out) if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): -- GitLab From 8e2ac3f704fdcc7ff51c275ff996c2175f3f7afe Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 13:47:23 +0200 Subject: [PATCH 27/36] added MASA test, currently fails for c08 --- ivas_processing_scripts/processing/evs.py | 12 +- tests/constants.py | 2 +- tests/data/test_MASA.yml | 295 ++++++++++++++++++++++ tests/data/test_SBA.yml | 2 +- tests/test_processing.py | 4 +- 5 files changed, 306 insertions(+), 9 deletions(-) create mode 100644 tests/data/test_MASA.yml diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 34719415..2a2cb1eb 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -277,12 +277,12 @@ class EVS(Processing): md_file_out = out_file.parent / (out_file.name + ".met") copyfile(md_file_in, md_file_out) # TODO: add next part for MASA - if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: - out_file_meta_unprocessed = ( - out_file.parent - / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" - ) - copyfile(in_meta[idx], out_file_meta_unprocessed) + # if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: + # out_file_meta_unprocessed = ( + # out_file.parent + # / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" + # ) + # copyfile(in_meta[idx], out_file_meta_unprocessed) elif out_file.suffix == ".txt": raise NotImplementedError(".txt file support is WIP") diff --git a/tests/constants.py b/tests/constants.py index c6731750..8e9abad4 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -197,7 +197,7 @@ HR_TRAJECTORIES_TO_TEST = [ """ Generate Test Items Configs """ INPUT_CONFIG_FILES = [ str(TEST_VECTOR_DIR.joinpath("test_ISM.yml")), - # str(TEST_VECTOR_DIR.joinpath("test_MASA.yml")), + str(TEST_VECTOR_DIR.joinpath("test_MASA.yml")), str(TEST_VECTOR_DIR.joinpath("test_MC.yml")), str(TEST_VECTOR_DIR.joinpath("test_SBA.yml")), ] diff --git a/tests/data/test_MASA.yml b/tests/data/test_MASA.yml new file mode 100644 index 00000000..b4a3eebd --- /dev/null +++ b/tests/data/test_MASA.yml @@ -0,0 +1,295 @@ +--- +################################################ +# General configuration +################################################ +### Name of test; default = YYYYMMDD_HH.MM.SS_listening_test +# name: test SBA +### Date; default = YYYYMMDD_HH.MM.SS +# date: 2023.06.30 +### git commit SHA; default = git rev-parse HEAD +# git_sha: abc123 + +### Whether to use multiprocessing; default = true +# multiprocessing: false +### Deletion of temporary directories containing +### intermediate processing files, bitstreams etc.; default = false +# delete_tmp: true +### Master seed for random processes like bitstream error pattern generation; default = 0 +master_seed: 5 + +### Any relative paths will be interpreted relative to the working directory the script is called from! +### Usage of absolute paths is recommended. +### Do not use file names with dots "." in them! This is not supported, use "_" instead +### For Windows user: please use double back slash '\\' in paths and add '.exe' to executable definitions +### REQUIRED: Input path or file +input_path: "./tests/concatenation_folder/MASA" +### REQUIRED: Output path or file +output_path: "./tests/temp_output_MASA" +### Metadata path or file(s) +### If input format is ISM{1-4} a path for the metadata files can be specified; +### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherise ignored) +# metadata_path: + ### Path can be set for all items with the 'all_items' key (automatic search for item_name.{wav, raw, pcm}.{0-3}.csv within this folder) + # all_items: ".../metadata_folder" + ### Path can be set for all items individually with 'item{1-4}' keys + ### 'item{1-4}' keys can also be renamed to the input file names including extension {wav, raw, pcm} + ### Either list individual files for all objects or name folder for automatic search for one item + # item1: + # - ".../meta_all_obj" + # item2: + # - ".../meta_obj1.csv" + # - ".../meta_ob2.csv" + # noise.wav: + # - ".../metadata_folder_for_noise_item" + +### Select only a subset of items +### searches for the specified substring in found filenames; default = null +# input_select: +# - "48kHz" + +################################################ +### Input configuration +################################################ +input: + ### REQUIRED: Input format + fmt: "FOA" + ### Input sampling rate in Hz needed for headerless audio files; default = 48000 + # fs: 32000 + +################################################ +### Pre-processing on individual items +################################################ +### Pre-processing step performed prior to core processing for all conditions +### If not defined, preprocessing step is skipped +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: 32000 + ### Target loudness in LKFS; default = null (no loudness change applied) + loudness: -30 + ### Spatial audio format in which loudness is adjusted (only used if preprocessing loudness is not null); + ### default = null (uses preprocessing fmt if possible) + # loudness_fmt: "MONO" + ### Pre-/post-trim individual signal(s) (ms) (negative values pad silence); default = 0 + # trim: + # - 50 + # - -50 + ### Flag for using noise (amplitude +-4) instead of silence for padding; default = false (silence) + # pad_noise: true + ### Value for application of delay (ms) (negative values advance); default = 0 + # delay: 20 + ### Length of window used at start/end of signal (ms); default = 0 + window: 100 + +################################################ +### Pre-processing on whole signal(s) +################################################ +preprocessing_2: + ### Options for processing of the concatenated item (concatenate_input: true) or + ### the individual items (concatenate_input: false) after previous pre-processing step + ### Horizontally concatenate input items into one long file; default = false + concatenate_input: true + ### 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 + ### Flag wheter to use noise (amplitude +-4) for the preamble or silence; default = false (silence) + preamble_noise: true + ### Additive background noise + # background_noise: + ### REQUIRED: SNR for background noise in dB + # snr: 10 + ### REQUIRED: Path to background noise, must have same format and sampling rate as input signal(s) + # background_noise_path: ".../noise.wav" + ### Seed for delay offest; default = 0 + # seed_delay: 10 + +################################################# +### Bitstream processing +################################################# +### Bitstream processing (transport simulation) done after encoding and before decoding +### e.g. frame error insertion or transport simulation for JBM testing +### can be given globally here or in individual conditions of type ivas or evs +# tx: + ### REQUIRED: Type of bitstream processing; possible types: "JBM" or "FER" + # type: "JBM" + + ### JBM + ### REQUIRED: either error_pattern or error_profile + ### delay error profile file + # error_pattern: ".../dly_error_profile.dat" + ### Index of one of the existing delay error profile files to use (1-11) + # error_profile: 5 + ## nFramesPerPacket parameter for the network simulator; default = 1 + # n_frames_per_packet: 2 + + ### FER + ### REQUIRED: either error_pattern or error_rate + ### Frame error pattern file + # error_pattern: "path/pattern.192" + ### Error rate in percent + # error_rate: 5 + ### Additional seed to specify number of preruns; default = 0 + # prerun_seed: 2 + +################################################ +### Configuration for conditions under test +################################################ +### List of conditions to generate +### Name of the key will be used as output directory name +### conditions must specify the "type" key which may be one of the following options: +### ref generate the reference condition +### lp3k5 generate a low-pass anchor with cut-off frequency 3.5 kHz +### lp7k generate a low-pass anchor with cut-off frequency 7 kHz +### mnru generate MNRU condition +### esdru generate ESDRU condition +### mono_dmx generate mono downmix condition +### evs generate an EVS coded condition (see below examples for additional required keys) +### ivas generate an IVAS coded condition (see below examples for additional required keys) +conditions_to_generate: + ### Reference and anchor conditions ########################## + c01: + ### REQUIRED: type of condition + type: ref + ### optional low-pass cut-off frequency in Hz; default = null + # out_fc: 22500 + c02: + ### REQUIRED: type of condition + type: lp7k + c03: + ### REQUIRED: type of condition + type: mnru + ### REQUIRED: the ratio of speech power to modulated noise power in dB + q: 20 + c04: + ### REQUIRED: type of condition + type: esdru + ### REQUIRED: spatial degradation value between 0 and 1 + alpha: 0.5 + + ### IVAS condition ############################### + c06: + ### REQUIRED: type of condition + type: ivas + ### REQUIRED: Bitrates to use for coding + bitrates: + - 160000 + # - 32000 + ### Encoder options + cod: + fmt: "MASA2" + ### Path to encoder binary; default search for IVAS_cod in bin folder (primary) and PATH (secondary) + #bin: ~/git/ivas-codec/IVAS_cod + ### Encoder input sampling rate in Hz (resampling performed in case of mismatch); default = null (no resampling) + # fs: 32000 + ### Additional commandline options; default = null + # opts: ["-q", "-dtx", 4] + ### Decoder options + dec: + ### Path to decoder binary; default search for IVAS_dec in bin folder (primary) and PATH (secondary) + #bin: ~/git/ivas-codec/IVAS_dec + ### Decoder output format; default = postprocessing fmt + fmt: "MASA2" + ### Decoder output sampling rate; default = null (same as input) + # fs: 48000 + ### Additional commandline options; default = null + # opts: ["-q", "-no_delay_cmp"] + ### Bitstream options + # tx: + ### For possible arguments see overall bitstream modification + + ### IVAS condition ############################### + c07: + ### REQUIRED: type of condition + type: ivas + ### REQUIRED: Bitrates to use for coding + bitrates: + - 160000 + # - 32000 + ### Encoder options + cod: + fmt: "MASA2" + ### Path to encoder binary; default search for IVAS_cod in bin folder (primary) and PATH (secondary) + #bin: ~/git/ivas-codec/IVAS_cod + ### Encoder input sampling rate in Hz (resampling performed in case of mismatch); default = null (no resampling) + # fs: 32000 + ### Additional commandline options; default = null + # opts: ["-q", "-dtx", 4] + ### Decoder options + dec: + ### Path to decoder binary; default search for IVAS_dec in bin folder (primary) and PATH (secondary) + #bin: ~/git/ivas-codec/IVAS_dec + ### Decoder output format; default = postprocessing fmt + # fmt: "CICP19" + ### Decoder output sampling rate; default = null (same as input) + # fs: 48000 + ### Additional commandline options; default = null + # opts: ["-q", "-no_delay_cmp"] + ### Bitstream options + tx: + ### For possible arguments see overall bitstream modification + type: "FER" + error_rate: 3 + prerun_seed: 2 + + ### EVS condition ################################ + c08: + ### REQUIRED: type of condition + type: evs + ### REQUIRED: Bitrates to use for coding + ### For EVS mono, this may be a per-channel bitrate configuration (must match input/preprocessing format!) + ### the last value will be repeated if too few are specified + bitrates: + # - 9600 + - [13200, 13200, 8000, 13200, 9600] + cod: + fmt: "MASA2" + ### Path to encoder binary; default search for EVS_cod in bin folder (primary) and PATH (secondary) + #bin: EVS_cod + ### Encoder input sampling rate in Hz (resampling performed in case of mismatch); default = null (no resampling) + # fs: 32000 + dec: + fmt: "MASA2" + ### Path to encoder binary; default search for EVS_dec in bin folder (primary) and PATH (secondary) + #bin: EVS_dec + ### Decoder output sampling rate; default = null (same as input) + # fs: 48000 + tx: + ### For possible arguments see overall bitstream modification + type: "FER" + error_rate: 3 + prerun_seed: 2 + +################################################ +### Post-processing +################################################ +### Post-processing step performed after core processing for all conditions +### Post-processing is required and can not be omitted +postprocessing: + ### REQUIRED: Target format for output + fmt: ["MASA2", "BINAURAL"] + ### REQUIRED: Target sampling rate in Hz for resampling + fs: 48000 + ### Low-pass cut-off frequency in Hz; default = null (no filtering) + # lp_cutoff: 24000 + ### Target loudness in LKFS; default = null (no loudness change applied) + loudness: -26 + ### Spatial audio format in which loudness is adjusted (only used if preprocessing loudness is not null); + ### default = null (uses postprocessing fmt if possible) + # loudness_fmt: null + ### Name of custom binaural dataset (without prefix or suffix); + ### default = null (ORANGE53(_Dolby) for BINAURAL, IISofficialMPEG222UC for BINAURAL_ROOM) + # bin_dataset: SADIE + ### Render LFE to binaural output with the specified gain (only valid for channel-based input); default = null + # bin_lfe_gain: 1 + ### Flag whether output should be limited to avoid clipping (can alter target loudness); default = false + limit: true + ### Head-tracking trajectory file for binaural output; default = null + # trajectory: "path/to/file" diff --git a/tests/data/test_SBA.yml b/tests/data/test_SBA.yml index 9bd98804..e5fedc5d 100644 --- a/tests/data/test_SBA.yml +++ b/tests/data/test_SBA.yml @@ -251,6 +251,7 @@ conditions_to_generate: # - 9600 - [13200, 13200, 8000, 13200, 9600] cod: + fmt: "PLANARFOA" ### Path to encoder binary; default search for EVS_cod in bin folder (primary) and PATH (secondary) #bin: EVS_cod ### Encoder input sampling rate in Hz (resampling performed in case of mismatch); default = null (no resampling) @@ -260,7 +261,6 @@ conditions_to_generate: #bin: EVS_dec ### Decoder output sampling rate; default = null (same as input) # fs: 48000 - sba_fmt: "PLANARFOA" ################################################ ### Post-processing diff --git a/tests/test_processing.py b/tests/test_processing.py index edf9f031..e9bdddc9 100644 --- a/tests/test_processing.py +++ b/tests/test_processing.py @@ -61,10 +61,12 @@ def test_generate_test_items(cfg): num_channels = 4 # test ISM4 elif "SBA" in cfg: num_channels = 4 # test FOA + elif "MASA" in cfg: + num_channels = 4 # test MASA with FOA input else: raise ValueError("Test setup missing") - # create input folder for MC, SBA and ISM tests with concatenation + # create input folder for MC, SBA, MASA and ISM tests with concatenation input_path.mkdir(exist_ok=True, parents=True) # copy items to folder -> pink noise and spectral test -- GitLab From eb2f7a16450d60ad8811fbe1d5afaa8397161270 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 14:08:17 +0200 Subject: [PATCH 28/36] fixed EVS for bitstream processing, loudness adjustement and MASA --- ivas_processing_scripts/processing/evs.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 2a2cb1eb..2a7886e2 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -276,13 +276,9 @@ class EVS(Processing): md_file_in = in_file.parent / (in_file.name + ".met") md_file_out = out_file.parent / (out_file.name + ".met") copyfile(md_file_in, md_file_out) - # TODO: add next part for MASA - # if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: - # out_file_meta_unprocessed = ( - # out_file.parent - # / f"{out_file.stem.split('.')[0]}.evs.noerror{out_file.suffix}.{idx}.csv" - # ) - # copyfile(in_meta[idx], out_file_meta_unprocessed) + if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: + md_file_out_noerror = out_file.parent / (Path(out_file_unprocessed).name + ".met") + copyfile(md_file_in, md_file_out_noerror) elif out_file.suffix == ".txt": raise NotImplementedError(".txt file support is WIP") -- GitLab From 0d0d3a91f399eab3a5af88b934d4e1250b66b2ba Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 14:27:53 +0200 Subject: [PATCH 29/36] added check to avoid unnecessary postprocessing steps --- ivas_processing_scripts/processing/chains.py | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index 474922fb..ca559324 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -349,7 +349,6 @@ def get_processing_chain( ) # update values to reflect decoder output tmp_in_fs = dec_cfg.get("fs", tmp_in_fs) - elif cond_cfg["type"] == "ivas": cod_cfg = cond_cfg["cod"] dec_cfg = cond_cfg["dec"] @@ -442,7 +441,6 @@ def get_processing_chain( # update values to reflect decoder output tmp_in_fs = dec_cfg.get("fs", tmp_in_fs) tmp_in_fmt = dec_cfg.get("fmt", tmp_out_fmt) - else: raise SystemExit(f"Unknown condition {condition}!") @@ -455,18 +453,19 @@ def get_processing_chain( # add Postprocessing with only format conversion for each format except the last fmts = [tmp_in_fmt] + pre_fmts for fmt_in, fmt_out in zip(fmts[:-1], fmts[1:]): - chain["processes"].append( - Postprocessing( - { - "in_fs": tmp_in_fs, - "in_fmt": fmt_in, - "out_fs": tmp_in_fs, - "out_fmt": fmt_out, - "tx_condition": tx_condition, - }, - name=f"post_{fmt_out}", + if fmt_in != fmt_out: + chain["processes"].append( + Postprocessing( + { + "in_fs": tmp_in_fs, + "in_fmt": fmt_in, + "out_fs": tmp_in_fs, + "out_fmt": fmt_out, + "tx_condition": tx_condition, + }, + name=f"post_{fmt_out}", + ) ) - ) tmp_in_fmt = fmt_out chain["processes"].append( -- GitLab From ab7b7a90eb9ec27f54146f95c676ec040cb969e0 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 15:03:50 +0200 Subject: [PATCH 30/36] fixed naming of EVS conditions with different bitrates for channels --- ivas_processing_scripts/processing/chains.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ivas_processing_scripts/processing/chains.py b/ivas_processing_scripts/processing/chains.py index ca559324..cf7f43b6 100755 --- a/ivas_processing_scripts/processing/chains.py +++ b/ivas_processing_scripts/processing/chains.py @@ -203,12 +203,11 @@ def get_processing_chain( ) -> dict: """Mapping from test configuration to condition and postprocessing keyword arguments""" name = f"{condition}" - # TODO related to naming TODO above if bitrate: - if isinstance(bitrate, list): - name += f"_{sum(bitrate)}" - else: - if multiple_bitrates is True: + if multiple_bitrates: + if isinstance(bitrate, list): + name += f"_{sum(bitrate)}" + else: name += f"_{bitrate}" chain = { -- GitLab From 17cf11c032678b7e8cdf52bec3550826e4c9d2b6 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 15:33:08 +0200 Subject: [PATCH 31/36] changed name of splitting info file to undo_concat --- ivas_processing_scripts/processing/processing.py | 5 +++-- .../processing/processing_splitting_scaling.py | 9 +-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index fef1e7a2..fa658810 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -156,12 +156,13 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger): cfg.items_list = [cfg.concat_file] # write out splits - with open(cfg.concat_file.with_suffix(".splits.log"), "w") as f: + splits_info_file = cfg.concat_file.parent.joinpath(Path("undo_concat.txt")) + with open(splits_info_file, "w") as f: print(", ".join([str(s) for s in cfg.splits]), file=f) print(", ".join([str(sn) for sn in cfg.split_names]), file=f) print(f"{fs}", file=f) - logger.info(f"Splits written to file {cfg.concat_file.with_suffix('.splits.log')}") + logger.info(f"Splits written to file {splits_info_file}") def concat_teardown(x, splits, out_fmt, fs, in_fs, meta, logger: logging.Logger): diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 03b7cfb6..085ba695 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -208,14 +208,7 @@ class Processing_splitting_scaling(Processing): # reverse concatenation if self.concatenate_input: # read out splits file -> start/end, names, sampling rate - if noerror: - splits_info_file = Path( - f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(Path(in_file.stem).stem).stem)}.splits.log" - ) - else: - splits_info_file = Path( - f"{in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath(Path(in_file.stem).stem)}.splits.log" - ) + splits_info_file = Path(in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath("undo_concat.txt")) splits, split_names, split_fs = read_splits_file(splits_info_file) # split file -- GitLab From c5aa75be04e3cd9deeebea6077dbb3a3fc0eec8d Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 15:34:19 +0200 Subject: [PATCH 32/36] formatting --- ivas_processing_scripts/processing/evs.py | 11 +++++++++-- .../processing/processing_splitting_scaling.py | 14 +++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 2a7886e2..22582359 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -239,7 +239,12 @@ class EVS(Processing): if split_chan_bs_unprocessed != split_chan_bs: apply_func_parallel( self.dec, - zip(split_chan_bs_unprocessed, split_chan_out_noerror, repeat(False), repeat(logger)), + zip( + split_chan_bs_unprocessed, + split_chan_out_noerror, + repeat(False), + repeat(logger), + ), None, "mt" if self.multiprocessing else None, show_progress=False, @@ -277,7 +282,9 @@ class EVS(Processing): md_file_out = out_file.parent / (out_file.name + ".met") copyfile(md_file_in, md_file_out) if split_chan_bs_unprocessed != split_chan_bs and self.tx_condition: - md_file_out_noerror = out_file.parent / (Path(out_file_unprocessed).name + ".met") + md_file_out_noerror = out_file.parent / ( + Path(out_file_unprocessed).name + ".met" + ) copyfile(md_file_in, md_file_out_noerror) elif out_file.suffix == ".txt": diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 085ba695..1c7f663e 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -153,9 +153,7 @@ class Processing_splitting_scaling(Processing): ) else: f_out = Path( - str(f) - .replace(tmp_name, out_name) - .replace(f".{self.name}.", ".") + str(f).replace(tmp_name, out_name).replace(f".{self.name}.", ".") ) out_out_files.append(f_out) if isinstance(audio.fromtype(self.out_fmt), audio.ObjectBasedAudio): @@ -208,7 +206,11 @@ class Processing_splitting_scaling(Processing): # reverse concatenation if self.concatenate_input: # read out splits file -> start/end, names, sampling rate - splits_info_file = Path(in_file.parent.parent.joinpath('tmp_preprocessing_2').joinpath("undo_concat.txt")) + splits_info_file = Path( + in_file.parent.parent.joinpath("tmp_preprocessing_2").joinpath( + "undo_concat.txt" + ) + ) splits, split_names, split_fs = read_splits_file(splits_info_file) # split file @@ -269,7 +271,9 @@ def adjust_loudness( file_splits, out_fmt, fs, loudness, loudness_fmt, meta, logger=None ): if logger: - logger.debug("Apply normal loudness scaling. The following loudness values are in the concatenation order.") + logger.debug( + "Apply normal loudness scaling. The following loudness values are in the concatenation order." + ) scaled_signals = [] for f, m in zip(file_splits, meta): audio_object = audio.fromarray(fmt=out_fmt, x=f, fs=fs) -- GitLab From 54049d433f96e126f90f12f9418cbfdce79a735b Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 15:51:29 +0200 Subject: [PATCH 33/36] format --- ivas_processing_scripts/processing/processing.py | 7 +------ .../processing/processing_splitting_scaling.py | 2 -- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index fa658810..97e76391 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -31,7 +31,6 @@ # import logging -import re from abc import ABC, abstractmethod from itertools import repeat from pathlib import Path @@ -43,15 +42,12 @@ import numpy as np from ivas_processing_scripts.audiotools import audio from ivas_processing_scripts.audiotools.audioarray import window -from ivas_processing_scripts.audiotools.audiofile import concat, read, trim, write +from ivas_processing_scripts.audiotools.audiofile import concat, read, trim from ivas_processing_scripts.audiotools.constants import IVAS_FRAME_LEN_MS from ivas_processing_scripts.audiotools.convert.__init__ import convert from ivas_processing_scripts.audiotools.metadata import ( add_remove_preamble, concat_meta_from_file, - metadata_search, - split_meta_in_file, - write_ISM_metadata_in_file, ) from ivas_processing_scripts.constants import LOGGER_DATEFMT, LOGGER_FORMAT from ivas_processing_scripts.processing.config import TestConfig @@ -166,7 +162,6 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger): def concat_teardown(x, splits, out_fmt, fs, in_fs, meta, logger: logging.Logger): - if not splits: raise ValueError("Splitting not possible without split marker") diff --git a/ivas_processing_scripts/processing/processing_splitting_scaling.py b/ivas_processing_scripts/processing/processing_splitting_scaling.py index 1c7f663e..af359b49 100644 --- a/ivas_processing_scripts/processing/processing_splitting_scaling.py +++ b/ivas_processing_scripts/processing/processing_splitting_scaling.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import copy import logging import re from itertools import repeat @@ -54,7 +53,6 @@ class Processing_splitting_scaling(Processing): self.name = "processing_splitting_scaling" def process(self, in_file: Path, out_file: Path, in_meta, logger: logging.Logger): - logger.debug(f"Processing splitting scaling configuration : {self.__dict__}") logger.debug(f"Processing splitting scaling {in_file.absolute()}") -- GitLab From 4df2b6654907b3c66173f3bea830144c5255e897 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 16:37:34 +0200 Subject: [PATCH 34/36] format and error instead of warning for no convergence in loudness loop --- ivas_processing_scripts/audiotools/wrappers/bs1770.py | 2 +- ivas_processing_scripts/processing/processing.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ivas_processing_scripts/audiotools/wrappers/bs1770.py b/ivas_processing_scripts/audiotools/wrappers/bs1770.py index f8052bc4..a808b2e6 100755 --- a/ivas_processing_scripts/audiotools/wrappers/bs1770.py +++ b/ivas_processing_scripts/audiotools/wrappers/bs1770.py @@ -291,7 +291,7 @@ def loudness_norm( ) if num_iter >= 10: - warn( + raise ValueError( f"Loudness did not converge to desired value, stopping at: {loudness_after:.2f}" ) diff --git a/ivas_processing_scripts/processing/processing.py b/ivas_processing_scripts/processing/processing.py index 97e76391..b2424cbd 100755 --- a/ivas_processing_scripts/processing/processing.py +++ b/ivas_processing_scripts/processing/processing.py @@ -366,7 +366,6 @@ def process_item( for im in range(len(in_meta)): out_meta.append(out_dir.joinpath(f"{Path(out_file).stem}.wav.{im}.csv")) - tx_condition = False # execute each process sequentially, feed output into input of next process for p, (input, output), input_meta in zip( chain, pairwise(processing_paths), processing_paths_meta[:-1] @@ -389,7 +388,6 @@ def process_item( def remove_preamble(x, out_fmt, fs, repeat_signal, preamble, meta, logger): - # remove preamble for ISM metadata if out_fmt.startswith("ISM"): # cut first half of the metadata -- GitLab From 8256ad72aa3c2889dbd2dabe613e844c0972820f Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 17:57:07 +0200 Subject: [PATCH 35/36] added quiet mode --- ivas_processing_scripts/processing/evs.py | 6 ++++++ ivas_processing_scripts/processing/ivas.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ivas_processing_scripts/processing/evs.py b/ivas_processing_scripts/processing/evs.py index 22582359..6697a71a 100755 --- a/ivas_processing_scripts/processing/evs.py +++ b/ivas_processing_scripts/processing/evs.py @@ -353,6 +353,9 @@ class EVS(Processing): cmd.extend(cod_opts) + # use quiet mode + cmd.extend(["-q"]) + cmd.extend( [ str(bitrate), @@ -434,6 +437,9 @@ class EVS(Processing): if self.dec_opts: cmd.extend(self.dec_opts) + # use quiet mode + cmd.extend(["-q"]) + cmd.extend([str(self.out_fs // 1000), str(bitstream), str(out_pcm_file)]) run(cmd, logger=logger) diff --git a/ivas_processing_scripts/processing/ivas.py b/ivas_processing_scripts/processing/ivas.py index 7dac592f..217f47ad 100755 --- a/ivas_processing_scripts/processing/ivas.py +++ b/ivas_processing_scripts/processing/ivas.py @@ -197,6 +197,9 @@ class IVAS(Processing): if self.cod_opts: cmd.extend(self.cod_opts) + # use quiet mode + cmd.extend(["-q"]) + fmt_codec = IVAS.parse_config(self.in_fmt, metadata_files) if fmt_codec == [""]: cmd.extend( @@ -293,6 +296,9 @@ class IVAS(Processing): if self.dec_opts: cmd.extend(self.dec_opts) + # use quiet mode + cmd.extend(["-q"]) + if self.out_fmt.name.startswith("ISM") or self.out_fmt.name.startswith("MASA"): output_format = "EXT" elif self.in_fmt.name == "MONO": -- GitLab From 11085ecf3fe920a64020261947df132912035839 Mon Sep 17 00:00:00 2001 From: Treffehn Date: Fri, 2 Jun 2023 18:03:18 +0200 Subject: [PATCH 36/36] changed loudness error back to warning --- ivas_processing_scripts/audiotools/wrappers/bs1770.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ivas_processing_scripts/audiotools/wrappers/bs1770.py b/ivas_processing_scripts/audiotools/wrappers/bs1770.py index a808b2e6..f8052bc4 100755 --- a/ivas_processing_scripts/audiotools/wrappers/bs1770.py +++ b/ivas_processing_scripts/audiotools/wrappers/bs1770.py @@ -291,7 +291,7 @@ def loudness_norm( ) if num_iter >= 10: - raise ValueError( + warn( f"Loudness did not converge to desired value, stopping at: {loudness_after:.2f}" ) -- GitLab