Commit f12cd70c authored by Archit Tamarapu's avatar Archit Tamarapu
Browse files

Merge branch '76-file-splitting-not-working-correctly-with-jbm' into 'main'

Resolve "File splitting not working correctly with JBM"

See merge request !186
parents c6b18040 09f530de
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ input_path: ".../ivas/items/HOA3"
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)
### default = null (for ISM search for item_name.{wav, raw, pcm}.{0-3}.csv in input folder, otherwise 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"
@@ -115,7 +115,7 @@ input:
    ### Horizontally concatenate input items into one long file; default = false
    # concatenate_input: true
    ### if concatenation is applied, the following two keys can be used to add zeros before or after the items
    ### duration is specified in miliseconds
    ### duration is specified in milliseconds
    # silence_pre: 2000
    # silence_post: 2000
    ### Specify the concatenation order in a list of strings. If not specified, the concatenation order would be
@@ -126,7 +126,7 @@ input:
    # 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)
    ### Flag whether to use noise (amplitude +-4) for the preamble or silence; default = false (silence)
    # preamble_noise: true
    ### Additive background noise
    # background_noise:
@@ -154,7 +154,7 @@ input:
    ### REQUIRED: either error_pattern (and errpatt_late_loss_rate or errpatt_delay) or error_profile
    ### delay error profile file
    # error_pattern: ".../dly_error_profile.dat"
    ### Late loss rate in precent for EVS
    ### Late loss rate in percent for EVS
    # errpatt_late_loss_rate: 1
    ### Constant JBM delay in milliseconds for EVS
    # errpatt_delay: 200
+4 −36
Original line number Diff line number Diff line
@@ -31,10 +31,7 @@
#

import logging
import sys
from itertools import product
from multiprocessing import Pool
from time import sleep

from ivas_processing_scripts.audiotools.metadata import (
    check_ISM_metadata,
@@ -53,12 +50,7 @@ from ivas_processing_scripts.processing.processing import (
    process_item,
    reorder_items_list,
)
from ivas_processing_scripts.utils import (
    DirManager,
    apply_func_parallel,
    progressbar_update,
    spinner,
)
from ivas_processing_scripts.utils import DirManager, apply_func_parallel


def logging_init(args, cfg):
@@ -190,34 +182,10 @@ def main(args):
                (item, tmp_dir, out_dir, chain["processes"], logger, metadata)
            )

        if cfg.multiprocessing:
            # set up values for progress display and chunksize
            count = len(item_args)
            width = 80

            # submit tasks to the pool
            p = Pool()
            results = p.starmap_async(
                process_item,
                item_args,
        apply_func_parallel(
            process_item, item_args, None, "mp" if cfg.multiprocessing else None, True
        )

            # poll progress
            progressbar_update(0, count, width)
            while not results.ready():
                progressbar_update(count - int(results._number_left), count, width)
                spinner()
                sleep(0.1)
            progressbar_update(count, count, width)
            print("", flush=True, file=sys.stdout)
            results.get()

            p.close()
            p.join()

        else:
            apply_func_parallel(process_item, item_args, None, None, True)

    # copy configuration to output directory
    cfg.to_file(cfg.output_path.joinpath(f"{cfg.name}.yml"))

+4 −2
Original line number Diff line number Diff line
@@ -376,7 +376,9 @@ def concat_meta_from_file(

    # add preamble
    if preamble:
        concat_meta_all_obj = add_remove_preamble(concat_meta_all_obj, preamble)
        concat_meta_all_obj = add_remove_metadata_preamble(
            concat_meta_all_obj, preamble
        )

    write_ISM_metadata_in_file(concat_meta_all_obj, out_file)

@@ -621,7 +623,7 @@ def metadata_search_MASA(
    return list_meta


def add_remove_preamble(
def add_remove_metadata_preamble(
    metadata,
    preamble,
    add: Optional[bool] = True,
+2 −2
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ from ivas_processing_scripts.audiotools import audio
from ivas_processing_scripts.audiotools.audioarray import trim
from ivas_processing_scripts.audiotools.audiofile import write
from ivas_processing_scripts.audiotools.metadata import (
    add_remove_preamble,
    add_remove_metadata_preamble,
    write_ISM_metadata_in_file,
)
from ivas_processing_scripts.audiotools.wrappers.bs1770 import (
@@ -83,7 +83,7 @@ class Preprocessing2(Processing):
            metadata = audio_object.object_pos

            # add preamble
            metadata = add_remove_preamble(metadata, preamble)
            metadata = add_remove_metadata_preamble(metadata, preamble)

            # repeat signal
            if self.repeat_signal:
+40 −108
Original line number Diff line number Diff line
@@ -31,35 +31,26 @@
#

import logging
import sys
from abc import ABC, abstractmethod
from itertools import repeat
from multiprocessing import Pool
from pathlib import Path
from shutil import copyfile
from time import sleep
from typing import Iterable, Union
from warnings import warn

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, 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,
    add_remove_metadata_preamble,
    concat_meta_from_file,
)
from ivas_processing_scripts.constants import LOGGER_DATEFMT, LOGGER_FORMAT
from ivas_processing_scripts.processing.config import TestConfig
from ivas_processing_scripts.utils import (
    list_audio,
    pairwise,
    progressbar_update,
    spinner,
)
from ivas_processing_scripts.processing.tx import get_timescaled_splits
from ivas_processing_scripts.utils import apply_func_parallel, list_audio, pairwise


class Processing(ABC):
@@ -202,7 +193,17 @@ def concat_setup(cfg: TestConfig, chain, logger: logging.Logger):


def concat_teardown(
    x, splits, out_fmt, fs, in_fs, meta, tracefile, ivas_jbm, logger: logging.Logger
    x,
    splits,
    out_fmt,
    fs,
    in_fs,
    meta,
    tracefile,
    ivas_jbm,
    repeat_signal,
    preamble,
    logger: logging.Logger,
):
    if splits is None:
        raise ValueError("Splitting not possible without split marker")
@@ -213,7 +214,7 @@ def concat_teardown(

    if (out_fmt.startswith("ISM") or out_fmt.startswith("MASA")) and ivas_jbm:
        raise ValueError(
            "Splitting with JBM compensation not supportet for formats with metadata (e.g. MASA, ISM)"
            "Splitting with JBM compensation not supported for formats with metadata (e.g. MASA, ISM)"
        )

    if logger and ivas_jbm:
@@ -228,59 +229,28 @@ def concat_teardown(
        relative_fs_change = fs_new / fs_old
        new_splits = [0]
        for split_i in splits:
            new_splits.append(int(float(split_i) * relative_fs_change))
            new_splits.append(int(split_i * relative_fs_change))
        splits = new_splits
    else:
        # adjust splits for jbm ivas conditions
        # following code is based on jbmtrim.cpp script
        rtpTimeScale = 1000  # in ms
        playTimeScale = 1000  # in ms
        new_splits = [None] * (len(splits) + 1)

        split_start = 1 / float(fs)
        i = 0
        lastRtpTs = 0
        lastPlayTime = 0
        # find last JBM trace entry with lower or equal RTP time stamp
        for j in range(tracefile.shape[0]):
            entry = tracefile[j]
            # ignore frames with unknown RTP time stamp or playout time
            if entry[1] == -1 or entry[3] < 0:
                continue
            # check if the next position to cut is found
            if entry[1] / rtpTimeScale >= split_start:
                # interpolate between current and previous RTP time stamp to
                # increase accuracy in case of DTX where lot of time stamps are missing
                if (num := entry[1] / rtpTimeScale - split_start) == 0:
                    rtpTsRelErr = num
                else:
                    rtpTsRelErr = num / (
                        ((entry[1] - lastRtpTs) / rtpTimeScale) + sys.float_info.epsilon
                    )
                playTimeAbsErr = rtpTsRelErr * (entry[3] - lastPlayTime) / playTimeScale
                # found one split, save in list and search for next
                new_splits[i] = entry[3] / playTimeScale - playTimeAbsErr
                # get next split marker; add one to make computation more similar to jbmtrim
                split_start = (float(splits[i]) + 1) / float(fs)
                i += 1
                if i >= len(new_splits):
                    break
            lastRtpTs = entry[1]
            lastPlayTime = entry[3]

        # check if all splits are found
        if i < (len(new_splits) - 1):
            raise ValueError("Error in item splitting with JBM compensation")
        elif i < (len(new_splits)):
            # catch item with missing end
            warn("Last split after end of file for IVAS JBM condition")
            new_splits[i] = lastPlayTime / playTimeScale

        # set new values and use new sampling rate
        splits = new_splits
        for s in range(len(splits)):
            # subtract one again (was only used to make computation more similar to jbmtrim)
            splits[s] = int(np.floor(splits[s] * float(in_fs))) - 1
        # handle signal repeat and preamble for JBM conditions since we have trace data

        # for preamble, the first split point should be at the end of the preamble
        preamble_smp = preamble * in_fs // 1000 if preamble > 0 else 0
        # for repeat signal, the first split point should be the start of the repetition
        repeat_start = preamble_smp + splits[-1] if repeat_signal else 0

        # adjust the offsets of the splits accordingly
        splits = [
            preamble_smp + repeat_start,
            *[s + preamble_smp + repeat_start for s in splits],
        ]

        splits_ts = get_timescaled_splits(tracefile, splits, fs, in_fs)

        # the above function assumes the starting point is the first playout frame
        # for repeat signal or preamble, we don't want the split to start there
        if repeat_signal or preamble > 0:
            splits = splits_ts[1:]

    # check if last split ending coincides with last sample of signal
    if splits[-1] > len(x):
@@ -331,10 +301,6 @@ def preprocess(cfg, logger):

    logger.info(f"  Generating condition: {preprocessing['name']}")

    # set up values for progress display and chunksize
    count = len(cfg.items_list)
    width = 80

    # run preprocessing
    args = list(
        zip(
@@ -346,25 +312,10 @@ def preprocess(cfg, logger):
            cfg.metadata_path,
        )
    )
    p = Pool()
    results = p.starmap_async(
        process_item,
        args,
    apply_func_parallel(
        process_item, args, None, "mp" if cfg.multiprocessing else None, True
    )

    # poll progress
    progressbar_update(0, count, width)
    while not results.ready():
        progressbar_update(count - int(results._number_left), count, width)
        spinner()
        sleep(0.1)
    progressbar_update(count, count, width)
    print("", flush=True, file=sys.stdout)
    results.get()

    p.close()
    p.join()

    # update the configuration to use preprocessing outputs as new inputs
    cfg.items_list = list_audio(
        cfg.out_dirs[0], select_list=getattr(cfg, "input_select", None)
@@ -427,10 +378,6 @@ def preprocess_2(cfg, logger):
    if chain[0].concatenate_input:
        concat_setup(cfg, chain, logger)

    # set up values for progress display and chunksize
    count = len(cfg.items_list)
    width = 80

    # run preprocessing 2
    args = list(
        zip(
@@ -442,25 +389,10 @@ def preprocess_2(cfg, logger):
            cfg.metadata_path,
        )
    )
    p = Pool()
    results = p.starmap_async(
        process_item,
        args,
    apply_func_parallel(
        process_item, args, None, "mp" if cfg.multiprocessing else None, True
    )

    # poll progress
    progressbar_update(0, count, width)
    while not results.ready():
        progressbar_update(count - int(results._number_left), count, width)
        spinner()
        sleep(0.1)
    progressbar_update(count, count, width)
    print("", flush=True, file=sys.stdout)
    results.get()

    p.close()
    p.join()

    # update the configuration to use preprocessing 2 outputs as new inputs
    cfg.items_list = list_audio(
        cfg.out_dirs[0], select_list=getattr(cfg, "input_select", None)
@@ -604,7 +536,7 @@ def remove_preamble(x, out_fmt, fs, repeat_signal, preamble_len_ms, meta, logger

        # remove preamble
        if preamble_len_ms > 0:
            meta = add_remove_preamble(meta, preamble_len_ms, add=False)
            meta = add_remove_metadata_preamble(meta, preamble_len_ms, add=False)

    # cut first half of signal
    if repeat_signal:
Loading