Commit 54a89b56 authored by Anika Treffehn's avatar Anika Treffehn
Browse files

added wrapper for evs jbm processing

parent 8546bbd9
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -139,9 +139,15 @@ input:
    # type: "JBM"
    
    ### JBM
    ### REQUIRED: either error_pattern or error_profile
    ### REQUIRED: either error_pattern (and errpatt_late_loss_rate or errpatt_delay and errpatt_seed for EVS) or error_profile
    ### delay error profile file
    # error_pattern: ".../dly_error_profile.dat"
    ### Late loss rate in precent or EVS
    # errpatt_late_loss_rate: 1
    ### Constant JBM delay in milliseconds for EVS
    # errpatt_delay: 200
    ### Seed for error pattern shift in EVS JBM
    # errpatt_seed: 0
    ### 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
+265 −0
Original line number Diff line number Diff line
#!/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 os.path
from pathlib import Path
from typing import Optional, Union
from warnings import warn

from ivas_processing_scripts.audiotools.wrappers.networkSimulator import LIST_JBM_PROFILES, ERROR_PATTERNS_DIR
from ivas_processing_scripts.constants import DEFAULT_CONFIG_BINARIES
from ivas_processing_scripts.utils import find_binary, run
from ivas_processing_scripts.audiotools.wrappers.eid_xor import eid_xor


def dlyerr_2_errpat(
    dlyerr_pattern: Union[str, Path],
    fer_pattern: Union[str, Path],
    length: Optional[int] = None,
    shift: Optional[int] = None,
    num_frames_packet: Optional[int] = None,
    late_loss_rate: Optional[int] = None,
    flag_byte: Optional[bool] = None,
    flag_word: Optional[bool] = None,
    flag_lf: Optional[bool] = None,
    delay: Optional[int] = None,
) -> None:
    """
    Wrapper for dlyerr_2_errpat binary to convert delay and error profiles to frame error patterns for EVS JBM
    bitstream processing

    Parameters
    ----------
    dlyerr_pattern: Union[str, Path]
        Path to delay and error pattern file
    fer_pattern: Union[str, Path]
        Path to frame error pattern file file
    length: Optional[int] = None
        length in frames
    shift: Optional[int] = None
        shift/offset in frames
    num_frames_packet: Optional[int] = None
        Number of frames per packet (1 or 2)
    late_loss_rate: Optional[int] = None
        Late loss rate in percent
    flag_byte: Optional[bool] = None
        Flag for using byte-oriented G.192 format (0x21 okay, 0x20 lost)
    flag_word: Optional[bool] = None
        Flag for using word-oriented G.192 format (0x6b21 okay, 0x6b20 lost)
    flag_lf: Optional[bool] = None
       Flag for using LF for text format to have one entry per line
    delay: Optional[int] = None
        Constant JBM delay in milliseconds
    """

    # find binary
    if "dlyerr_2_errpat" in DEFAULT_CONFIG_BINARIES["binary_paths"]:
        binary = find_binary(
            DEFAULT_CONFIG_BINARIES["binary_paths"]["dlyerr_2_errpat"].name,
            binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"]["dlyerr_2_errpat"].parent,
        )
    else:
        binary = find_binary("dlyerr_2_errpat")

    # check for valid inputs
    if not Path(dlyerr_pattern).is_file():
        raise ValueError(
            f"Delay and error pattern file {dlyerr_pattern} for bitstream processing does not exist"
        )
    if delay is not None and late_loss_rate is not None:
        raise ValueError("Can't scpecify delay and late loss rate for dlyerr_2_err tool but only one of them")

    # set up command line
    cmd = [
        str(binary),
        "-i",  # input file
        str(dlyerr_pattern),
        "-o",  # output file
        str(fer_pattern),
    ]

    if length is not None:
        cmd.extend(["-L", str(length)])
    if shift is not None:
        cmd.extend(["-s", str(shift)])
    if num_frames_packet is not None:
        cmd.extend(["-f", str(num_frames_packet)])
    if late_loss_rate is not None:
        cmd.extend(["-l", str(late_loss_rate)])
    if flag_byte is not None:
        cmd.extend(["-b", str(flag_byte)])
    if flag_word is not None:
        cmd.extend(["-w", str(flag_word)])
    if flag_lf is not None:
        cmd.extend(["-c", str(flag_lf)])
    if delay is not None:
        cmd.extend(["-d", str(delay)])

    # run command
    run(cmd)

    return


def evs_jbm(bitstream, bitstream_processed, error_profile, error_pattern, errpatt_late_loss_rate, errpatt_delay, errpatt_seed, errpatt_frames_packet):

    # convert delay and error profile
    delay = None
    num_frames_packet = None
    shift = None
    late_loss_rate = None
    length = None
    flag_word = True

    if error_pattern is not None:
        # if error pattern and parameter are specified
        delay = errpatt_delay
        late_loss_rate = errpatt_late_loss_rate
        num_frames_packet = errpatt_frames_packet
        shift = 0   # TODO: (treffehn) compute offset with random and master seed (also for ivas jbm)
        dlyerr_pattern = error_pattern
    elif error_profile is not None:
        # if eror profile number is given
        if error_profile == 1 or error_profile == 2 or error_profile == 3:
            delay = 200
            num_frames_packet = 1
        elif error_profile == 4 or error_profile == 6:
            late_loss_rate = 1
            num_frames_packet = 1
        elif error_profile == 5:
            late_loss_rate = 1
            num_frames_packet = 2
        elif error_profile == 7 or error_profile == 8 or error_profile == 9:
            delay = 200
            num_frames_packet = 1
            length = 8000
        elif error_profile == 10:
            late_loss_rate = 1
            num_frames_packet = 1
            length = 8000
        else:
            # TODO: (treffehn) what to do?
            raise ValueError("JBM error profile number not an integer between 1 and 10")
        shift = 0  # TODO: (treffehn) compute offset with random and master seed (also for ivas jbm)
        if error_profile in LIST_JBM_PROFILES:
            dlyerr_pattern = ERROR_PATTERNS_DIR.joinpath(
                f"dly_error_profile_{error_profile}.dat"
            )
        else:
            raise ValueError(
                f"JBM profile number {error_profile} does not exist, should be between {LIST_JBM_PROFILES[0]} and {LIST_JBM_PROFILES[-1]}"
            )

    fer_pattern = Path(bitstream).with_suffix(".evs_jbm_fer.192")

    dlyerr_2_errpat(
        dlyerr_pattern=dlyerr_pattern,
        fer_pattern=fer_pattern,
        delay=delay,
        num_frames_packet=num_frames_packet,
        flag_word=flag_word,
        shift=shift,
        late_loss_rate=late_loss_rate,
        length=length,
    )

    # apply FER pattern with eid-xor
    # TODO (treffehn)
    # eid_xor()


def validate_evs_jbm(
    error_pattern: Optional[Union[Path, str]] = None,
    error_profile: Optional[int] = None,
    errpatt_late_loss_rate: Optional[int] = None,
    errpatt_delay: Optional[int] = None,
    errpatt_seed: Optional[int] = None,
    n_frames_per_packet: Optional[int] = None,
) -> None:
    """
    Validate settings for the EVS JBM processing

    Parameters
    ----------
    error_pattern: Optional[Union[Path, str]]
        Path to existing error pattern
    error_profile: Optional[int]
        Index of existing error pattern
    errpatt_late_loss_rate: Optional[int]
        Late loss rate in precent or EVS
    errpatt_delay: Optional[int]
        Constant JBM delay in milliseconds for EVS
    errpatt_seed: Optional[int]
        Seed for error pattern shift in EVS JBM
    n_frames_per_packet: Optional[int]
        Number of frames per paket
    """

    if "dlyerr_2_errpat" in DEFAULT_CONFIG_BINARIES["binary_paths"]:
        binary = find_binary(
            DEFAULT_CONFIG_BINARIES["binary_paths"]["dlyerr_2_errpat"].name,
            binary_path=DEFAULT_CONFIG_BINARIES["binary_paths"][
                "dlyerr_2_errpat"
            ].parent,
        )
    else:
        binary = find_binary("dlyerr_2_errpat")

    if binary is None:
        raise FileNotFoundError(
            "The dlyerr_2_errpat binary for EVS JBM conditions was not found! Please check the configuration."
        )
    if error_pattern is not None:
        if not Path(error_pattern).exists():
            raise FileNotFoundError(
                f"The EVS JBM error profile file {error_pattern} was not found! Please check the configuration."
            )
        if error_profile is not None:
            raise ValueError(
                "JBM pattern and JBM profile number are specified for bitstream processing. Can't use both! Please check the configuration."
            )
        if errpatt_late_loss_rate is not None and errpatt_delay is not None:
            raise ValueError("For EVS JBM conditions with error pattern only late loss rate OR delay has to be specified, not both!")
        if errpatt_late_loss_rate is None and errpatt_delay is None:
            raise ValueError("For EVS JBM conditions with error pattern either late loss rate or delay has to be specified!")
        if errpatt_seed is None:
            warn("No seed was specified for EVS JBM offset -> Use 0")
    elif error_profile is not None:
        if error_profile not in LIST_JBM_PROFILES:
            raise ValueError(
                f"JBM profile number {error_profile} does not exist, should be between {LIST_JBM_PROFILES[0]} and {LIST_JBM_PROFILES[-1]}"
            )
    if n_frames_per_packet is not None and n_frames_per_packet not in [1, 2]:
        raise ValueError(
            f"n_frames_per_paket is {n_frames_per_packet}. Should be 1 or 2. Please check your configuration."
        )
    return
+1 −0
Original line number Diff line number Diff line
@@ -14,3 +14,4 @@ Necessary additional executables:
| JBM network simulator                           | networkSimulator_g192 | https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_76/docs/S4-131277.zip                                       |
| MASA rendering (also used in loudness measurement of MASA items)        | masaRenderer        | https://www.3gpp.org/ftp/TSG_SA/WG4_CODEC/TSGS4_122_Athens/Docs/S4-230221.zip                               |
| EVS reference conditions        | EVS_cod, EVS_dec      | https://www.3gpp.org/ftp/Specs/archive/26_series/26.443/26443-h00.zip                                       |
| EVS JBM conditions | dlyerr_2_errpat | http://ftp.3gpp.org/tsg_sa/WG4_CODEC/TSGS4_70/Docs/S4-121077.zip |
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -30,3 +30,5 @@
# masaRenderer: "path/to/binary/masaRenderer"
# ### Binary for reverberation
# reverb: "path/to/binary/reverb"
# ### Binary for EVS JBM error pattern conversion tool
# dlyerr_2_errpat: "path/to/binary/dlyerr_2_errpat"
+3 −0
Original line number Diff line number Diff line
@@ -302,6 +302,9 @@ def get_processing_chain(
                    "error_pattern": get_abs_path(
                        tx_cfg_tmp.get("error_pattern", None)
                    ),
                    "errpatt_late_loss_rate": tx_cfg_tmp.get("errpatt_late_loss_rate", None),
                    "errpatt_delay": tx_cfg_tmp.get("errpatt_delay", None),
                    "errpatt_seed": tx_cfg_tmp.get("errpatt_seed", None),
                    "error_profile": tx_cfg_tmp.get("error_profile", None),
                    "n_frames_per_packet": tx_cfg_tmp.get("n_frames_per_packet", None),
                }
Loading