diff --git a/.gitignore b/.gitignore index de9e357339c5e1b336f2e9cc0c9e58a8da5d4199..ec453aa92e6f3c571795d2e67ff1a12e27acb663 100644 --- a/.gitignore +++ b/.gitignore @@ -48,9 +48,9 @@ tests/**/ref tests/*/testv scripts/testv/*_cut*.pcm # default reference binary name -IVAS_cod_ref -IVAS_dec_ref -IVAS_rend_ref +IVAS_cod_ref* +IVAS_dec_ref* +IVAS_rend_ref* # Python files that pop up when running scripts __pycache__/ diff --git a/.gitlab-ci-custom.yml b/.gitlab-ci-custom.yml index 86c1f487e07710b92454a0c4f7690f171d0f6ac4..89cc0a6a4bbbfdae1ffee2294e8f9bd930642aeb 100644 --- a/.gitlab-ci-custom.yml +++ b/.gitlab-ci-custom.yml @@ -1,4 +1,1142 @@ -include: - - project: $CUSTOM_CI_PROJECT - ref: $CUSTOM_CI_REF - file: $CUSTOM_CI_FILE +# include: +# - project: $CUSTOM_CI_PROJECT +# ref: $CUSTOM_CI_REF +# file: $CUSTOM_CI_FILE + +# Copied from ivas-ci:main + +variables: + # Variables as used in external repo (may be altered in value, see comments) + TESTV_DIR: "/usr/local/testv" + LTV_DIR: "/usr/local/ltv" + BUILD_OUTPUT: "build_output.txt" + EVS_BE_TEST_DIR: "/usr/local/be_2_evs_test" + SANITIZER_TESTS: "CLANG1 CLANG2" + OUT_FORMATS_CHANNEL_BASED: "stereo mono 5_1 5_1_2 5_1_4 7_1 7_1_4" + OUT_FORMATS_SCENE_BASED: "FOA HOA2 HOA3" + OUT_FORMATS_BINAURAL: "BINAURAL BINAURAL_ROOM_IR BINAURAL_ROOM_REVERB" + EXIT_CODE_NON_BE: 123 + EXIT_CODE_FAIL: 1 + # Variables for FhG internal jobs + UPSTREAM_URL: "https://forge.3gpp.org/rep/ivas-codec-pc/ivas-codec/" + INTERNAL_TESTV_DIR: "/testv" + INTERNAL_CI_REPO_CLONE_DIR: "ivas-internal-ci" + GIT_SUBMODULE_STRATEGY: recursive + + +# This sets when pipelines are created. Jobs have more specific rules to restrict them. +workflow: + rules: + # see https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" + when: never + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' # Runs for merge requests + - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Pushes to main + - if: $CI_PIPELINE_SOURCE == 'schedule' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Scheduled in main + - if: $CI_PIPELINE_SOURCE == 'web' # Scheduled in main + + +stages: + - mirroring-pre-test + - build + - test + - compare + - validate + - mirroring-post-test + +# --------------------------------------------------------------- +# Generic script anchors +# --------------------------------------------------------------- + +# These can be used later on to do common tasks + +# Prints useful information for every job and should be used at the beginning of each job +.print-common-info: &print-common-info + - | + echo "Printing common information for build job." + echo "Current job is run on commit $CI_COMMIT_SHA" + echo "Commit time was $CI_COMMIT_TIMESTAMP" + date | xargs echo "System time is" + +.get-previous-merge-commit-sha: &get-previous-merge-commit-sha + - previous_merge_commit=$(git --no-pager log --merges HEAD~1 -n 1 --pretty=format:%H) + +.mr-fetch-target-branch: &mr-fetch-target-branch + # first delete local target branch to avoid conflicts when branch is cached and there are merge conflicts during fetching + # depending on chaching, the branch may not be there, so prevent failure of this command -> should maybe be done smarter later + - git branch -D $CI_MERGE_REQUEST_TARGET_BRANCH_NAME || true + # needed when depth is lower than the number of commits in the branch + - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME:$CI_MERGE_REQUEST_TARGET_BRANCH_NAME + +.mr-get-target-commit: &mr-get-target-commit + # compare to last target branch commit before pipeline was created + - target_commit=$(git log $CI_MERGE_REQUEST_TARGET_BRANCH_NAME -1 --oneline --before=${CI_PIPELINE_CREATED_AT} --format=%H) + +# [INTERNAL] clone the ivas-internal-ci repo +.get-ivas-internal-ci-repo: &get-ivas-internal-ci-repo + - git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@$CI_SERVER_HOST/$CUSTOM_CI_PROJECT $INTERNAL_CI_REPO_CLONE_DIR + +# [INTERNAL] use this anchor to copy over the "old" internal testv/ files +.overwrite-testv-with-internal-ones: &overwrite-testv-with-internal-ones + - cp $INTERNAL_CI_REPO_CLONE_DIR/internal-testv/* scripts/testv/ + +# [INTERNAL] use for getting the sanitizer testvectors from ivas-internal-ci +.get-internal-ltv-signals: &get-internal-ltv-signals + # overwrite config + - cp $INTERNAL_CI_REPO_CLONE_DIR/scripts/ci_sanitizers_fhg_testv.json scripts/config/ci_linux_ltv.json + # copy files + - if [ ! -d "$LTV_DIR" ]; then mkdir -p $LTV_DIR; fi + - cp $INTERNAL_CI_REPO_CLONE_DIR/internal-ltv/* $LTV_DIR/ + +# --------------------------------------------------------------- +# Job templates +# --------------------------------------------------------------- + +# When designing templates, try not to use too much inheritance and +# if multiple templates and extended on, remember that on conflict, +# latest overwrites the parameter. + +# templates for rules +.rules-basis: + rules: + - if: $MIRROR_ACCESS_TOKEN # Don't run in the mirror update pipeline (only then MIRROR_ACCESS_TOKEN is defined) + when: never + - when: on_success + - if: $CI_PIPELINE_SOURCE == 'schedule' # Don't run in any scheduled pipelines by default (use schedule templates below to enable again for certain conditions) + when: never + - when: on_success + +.rules-merge-request: + extends: .rules-basis + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_PIPELINE_SOURCE == 'push' + when: never + +.rules-main-push: + extends: .rules-basis + rules: + - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +.rules-main-scheduled: + extends: .rules-basis + rules: + - if: $CI_PIPELINE_SOURCE == 'schedule' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + + +# templates to define stages and platforms + +# differs from forge -> we use docker image here +.test-job-linux: + tags: + - exec::docker + image: $CUSTOM_CI_REGISTRY/ubuntu_22.04:latest + +# differs from forge -> we use docker image here +.build-job-linux: + stage: build + # more time internally to accomodate for the shared runners + timeout: "4 minutes" + tags: + - exec::docker + image: $CUSTOM_CI_REGISTRY/ubuntu_22.04:latest + + +# template for test jobs on linux that need the TESTV_DIR +.test-job-linux-needs-testv-dir: + extends: .test-job-linux + tags: + - exec::docker + - res::ivas-testv + before_script: + - if [ ! -d "$TESTV_DIR" ]; then mkdir -p $TESTV_DIR; fi + - cp -r scripts/testv/* $TESTV_DIR/ + +# [INTERNAL] use the internal testvectors for self_test.prm items +.test-job-linux-needs-internal-testv-dir: + extends: .test-job-linux + tags: + - exec::docker + - res::ivas-testv + before_script: + - if [ ! -d "$TESTV_DIR" ]; then mkdir -p $TESTV_DIR; fi + # first copy external testvectors, then overwrite with internal ones + # this way, newly added vectors that have no internal pendent are not missing + - cp -r scripts/testv/* $TESTV_DIR/ + - cp -r $INTERNAL_TESTV_DIR/* $TESTV_DIR/ + +# [INTERNAL] copy "old" internal testvectors to scripts/testv to use them in self_test.prm-based test +.test-job-linux-with-internal-selftest-vectors: + extends: .test-job-linux + tags: + - exec::docker + - res::ivas-testv + before_script: + - cp -r $INTERNAL_TESTV_DIR/* ./scripts/testv/ + +# template for build jobs to include the check for warnings +.build-job-with-check-for-warnings: + extends: .build-job-linux + stage: build + allow_failure: + exit_codes: + - 123 + + +# --------------------------------------------------------------- +# Build jobs +# --------------------------------------------------------------- + +build-codec-linux-make: + extends: + - .build-job-with-check-for-warnings + - .rules-basis + script: + - *print-common-info + - make -j 2>&1 | tee $BUILD_OUTPUT + # need to use the "|| exit $?" suffix to get the allowed_failure return code, otherwise the job fails with code 1...< + - ci/check_for_warnings.py $BUILD_OUTPUT || exit $? + +build-codec-linux-cmake: + extends: + - .build-job-with-check-for-warnings + - .rules-basis + script: + - *print-common-info + - mkdir build + - cd build + - cmake .. + - cd .. + - make -C build -j 2>&1 | tee $BUILD_OUTPUT + # need to use the "|| exit $?" suffix to get the allowed_failure return code, otherwise the job fails with code 1...< + - ci/check_for_warnings.py $BUILD_OUTPUT || exit $? + +build-codec-instrumented-linux: + extends: + - .build-job-linux + - .rules-basis + script: + - *print-common-info + - bash ci/build_codec_instrumented_linux.sh + allow_failure: true # TODO(sgi): Remove + +# make sure that the codec builds with msan, asan and usan +build-codec-sanitizers-linux: + extends: + - .build-job-linux + - .rules-basis + script: + - *print-common-info + - bash ci/build_codec_sanitizers_linux.sh + + +# --------------------------------------------------------------- +# Test jobs for merge requests +# --------------------------------------------------------------- + +# test that runs all modes with 1s input signals +codec-smoke-test: + extends: + - .test-job-linux-needs-internal-testv-dir + - .rules-merge-request + timeout: "5 minutes" + stage: test + needs: [ "build-codec-linux-cmake" ] + script: + - *print-common-info + - bash ci/smoke_test.sh + ### analyze for failures + - if cat smoke_test_output.txt | grep -c "failed"; then echo "Smoke test without PLC failed"; exit 1; fi + - if cat smoke_test_output_plc.txt | grep -c "failed"; then echo "Smoke test with PLC failed"; exit 1; fi + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + when: always + paths: + - out/logs/ + - smoke_test_output.txt + - smoke_test_output_plc.txt + expose_as: 'Smoke test results' + allow_failure: true # TODO(sgi): Remove + + +# code selftest testvectors with memory-sanitizer binaries +msan-on-merge-request-linux: + extends: + - .test-job-linux + - .rules-merge-request + stage: test + needs: [ "build-codec-sanitizers-linux" ] + script: + - *print-common-info + - make clean + - make -j CLANG=1 + - python3 scripts/self_test.py --create | tee test_output.txt + - run_errors=$(cat test_output.txt | grep -ic "run errors") || true + - if [ $run_errors != 0 ] ; then echo "Run errors in self_test.py with Clang memory-sanitizer"; exit 1; fi + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + paths: + - scripts/ref/logs/ + - test_output.txt + expose_as: 'Msan selftest results' + + +# code selftest testvectors with address-sanitizer binaries +asan-on-merge-request-linux: + extends: + - .test-job-linux + - .rules-merge-request + stage: test + needs: [ "build-codec-sanitizers-linux" ] + script: + - *print-common-info + - make clean + - make -j CLANG=2 + - python3 scripts/self_test.py --create | tee test_output.txt + - run_errors=$(cat test_output.txt | grep -ic "run errors") || true + - if [ $run_errors != 0 ] ; then echo "Run errors in self_test.py with Clang address-sanitizer"; exit 1; fi + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + paths: + - scripts/ref/logs/ + - test_output.txt + expose_as: 'Asan selftest results' + +# test renderer executable +renderer-smoke-test: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-make"] + stage: test + script: + - make -j IVAS_rend + - python3 -m pytest -q -n auto -rA --junit-xml=report-junit.xml tests/renderer/test_renderer.py + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--job-$CI_JOB_NAME--results" + when: always + paths: + - report-junit.xml + expose_as: "renderer make pytest results" + reports: + junit: + - report-junit.xml + +# test renderer executable with cmake + asan +renderer-asan: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-cmake"] + stage: test + script: + - python3 ci/disable_ram_counting.py + - cmake -B cmake-build -G "Unix Makefiles" -DCLANG=asan -DCOPY_EXECUTABLES_FROM_BUILD_DIR=true + - cmake --build cmake-build -- -j + - python3 -m pytest -q -n auto -rA --junit-xml=report-junit.xml tests/renderer/test_renderer.py + + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--job-$CI_JOB_NAME--results" + when: always + paths: + - report-junit.xml + expose_as: "renderer asan pytest results" + reports: + junit: + - report-junit.xml + +# test renderer executable with cmake + msan +renderer-msan: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-cmake"] + stage: test + script: + - python3 ci/disable_ram_counting.py + - cmake -B cmake-build -G "Unix Makefiles" -DCLANG=msan -DCOPY_EXECUTABLES_FROM_BUILD_DIR=true + - cmake --build cmake-build -- -j + - python3 -m pytest -q -n auto -rA --junit-xml=report-junit.xml tests/renderer/test_renderer.py + + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--job-$CI_JOB_NAME--results" + when: always + paths: + - report-junit.xml + expose_as: "renderer msan pytest results" + reports: + junit: + - report-junit.xml + + +renderer-5ms-framing-asan: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-cmake"] + stage: test + script: + # Build reference executable - 5ms framing disabled + - cp lib_com/options.h lib_com/options.h.bak + - sed -i '/API_5MS/d' lib_com/options.h + - cmake -B cmake-build-ref . + - cmake --build cmake-build-ref -- -j + - cp cmake-build-ref/IVAS_rend IVAS_rend_ref_5ms + + # Build test executable + - mv -f lib_com/options.h.bak lib_com/options.h + - cmake -B cmake-build -DCLANG=asan . + - cmake --build cmake-build -- -j + - cp cmake-build/IVAS_rend . + + # Run Razel test + - scripts/razel/test_renderer_razel.py + +renderer-5ms-framing-msan: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-cmake"] + stage: test + script: + # Build reference executable - 5ms framing disabled + - cp lib_com/options.h lib_com/options.h.bak + - sed -i '/API_5MS/d' lib_com/options.h + - cmake -B cmake-build-ref . + - cmake --build cmake-build-ref -- -j + - cp cmake-build-ref/IVAS_rend IVAS_rend_ref_5ms + + # Build test executable + - mv -f lib_com/options.h.bak lib_com/options.h + - cmake -B cmake-build -DCLANG=msan . + - cmake --build cmake-build -- -j + - cp cmake-build/IVAS_rend . + + # Run Razel test + - scripts/razel/test_renderer_razel.py + +.merge-request-comparison-setup-codec: + &merge-request-comparison-setup-codec ### build test binaries, initial clean for paranoia reasons + - make clean + - mkdir build + - cd build + - cmake .. + - make -j + - mv IVAS_cod ../IVAS_cod_test + - mv IVAS_dec ../IVAS_dec_test + - mv IVAS_rend .. + - cd .. + - rm -rf build/* + + ### store the current commit hash + - source_branch_commit_sha=$(git rev-parse HEAD) + + ### checkout version to compare against + - *mr-fetch-target-branch + + - *mr-get-target-commit + - git checkout $target_commit + + ### build reference binaries + - cd build + - cmake .. + - make -j + - mv IVAS_cod ../IVAS_cod_ref + - mv IVAS_dec ../IVAS_dec_ref + - cd .. + + # rename test binaries back + - mv IVAS_cod_test IVAS_cod + - mv IVAS_dec_test IVAS_dec + +.merge-request-comparison-check: &merge-request-comparison-check + - if [ $zero_errors != 1 ]; then echo "Run errors encountered!"; exit $EXIT_CODE_FAIL; fi + - if [ $exit_code -eq 1 ] && [ $non_be_flag == 0 ]; then echo "Non-bitexact cases without non-BE tag encountered!"; exit $EXIT_CODE_FAIL; fi + - if [ $exit_code -eq 1 ] && [ $non_be_flag != 0 ]; then echo "Non-bitexact cases with non-BE tag encountered"; exit $EXIT_CODE_NON_BE; fi + - exit 0 + +# compare renderer bitexactness between target and source branch +renderer-pytest-on-merge-request: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-make"] + # TODO: set reasonable timeout, will most likely take less + timeout: "20 minutes" + stage: compare + script: + - *print-common-info + + # some helper variables - "|| true" to prevent failures from grep not finding anything + - non_be_flag=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[rend\(erer\)*[ -]*non[ -]*be\]") || true + # TODO: needs splitting the test between reference and cut generation + #- ref_using_main=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[ref[ -]*using[ -]*main\]") || true + + # store the current commit hash + - source_branch_commit_sha=$(git rev-parse HEAD) + + - *mr-fetch-target-branch + - *mr-get-target-commit + - git checkout $target_commit + + # build reference binaries + - make -j IVAS_rend + - mv IVAS_rend IVAS_rend_ref + + # back to source branch + - git checkout $source_branch_commit_sha + - make clean + - make -j IVAS_rend + + # run test + - exit_code=0 + - python3 -m pytest -q --log-level ERROR -n auto -rA --html=report.html --self-contained-html --junit-xml=report-junit.xml tests/renderer/test_renderer_be_comparison.py || exit_code=$? + - zero_errors=$(cat report-junit.xml | grep -c 'errors="0"') || true + + - *merge-request-comparison-check + + allow_failure: + exit_codes: + - 123 + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--job-$CI_JOB_NAME--results" + when: always + paths: + - report-junit.xml + - report.html + expose_as: "pytest renderer results" + reports: + junit: + - report-junit.xml + +# compare bit exactness between target and source branch +# [INTERNAL] this uses our own testvectors internally! +ivas-pytest-on-merge-request: + extends: + - .test-job-linux + - .rules-merge-request + stage: compare + needs: ["build-codec-linux-cmake", "codec-smoke-test"] + timeout: "10 minutes" + script: + - *print-common-info + - *merge-request-comparison-setup-codec + - *get-ivas-internal-ci-repo + - *overwrite-testv-with-internal-ones + + # some helper variables - "|| true" to prevent failures from grep not finding anything + - non_be_flag=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[non[ -]*be\]") || true + - ref_using_main=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[ref[ -]*using[ -]*main\]") || true + + ### If ref_using_main is not set, checkoug the source branch to use scripts and input from there + - if [ $ref_using_main == 0 ]; then git checkout $source_branch_commit_sha; fi + + ### prepare pytest + # create short test vectors + - python3 tests/create_short_testvectors.py + # create references + - python3 -m pytest tests -v --update_ref 1 -m create_ref + - python3 -m pytest tests -v --update_ref 1 -m create_ref_part2 + + ### Run test using branch scripts and input + - if [ $ref_using_main == 1 ]; then git checkout $source_branch_commit_sha; fi + + ### run pytest + - exit_code=0 + - python3 -m pytest tests -v --junit-xml=report-junit.xml || exit_code=$? + - zero_errors=$(cat report-junit.xml | grep -c 'errors="0"') || true + + - *merge-request-comparison-check + + allow_failure: + exit_codes: + - 123 + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + when: always + paths: + - report-junit.xml + expose_as: "pytest ivas results" + reports: + junit: + - report-junit.xml + +# compare external renderer bitexactness between target and source branch +external-renderer-pytest-on-merge-request: + extends: + - .test-job-linux + - .rules-merge-request + needs: ["build-codec-linux-make"] + # TODO: set reasonable timeout, will most likely take less + timeout: "20 minutes" + stage: compare + script: + - *print-common-info + + # some helper variables - "|| true" to prevent failures from grep not finding anything + - non_be_flag=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[rend\(erer\)*[ -]*non[ -]*be\]") || true + # TODO: needs splitting the test between reference and cut generation + #- ref_using_main=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[ref[ -]*using[ -]*main\]") || true + + # store the current commit hash + - source_branch_commit_sha=$(git rev-parse HEAD) + + - *mr-fetch-target-branch + - *mr-get-target-commit + - git checkout $target_commit + + # build reference binaries + - make -j IVAS_rend + - mv IVAS_rend IVAS_rend_ref + + # back to source branch + - git checkout $source_branch_commit_sha + - make clean + - make -j IVAS_rend + + # run test + - exit_code=0 + - python3 -m pytest -q --log-level ERROR -n auto -rA --html=report.html --self-contained-html --junit-xml=report-junit.xml tests/renderer/test_renderer_be_comparison.py || exit_code=$? + - zero_errors=$(cat report-junit.xml | grep -c 'errors="0"') || true + + - *merge-request-comparison-check + + allow_failure: + exit_codes: + - 123 + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--job-$CI_JOB_NAME--results" + when: always + paths: + - report-junit.xml + - report.html + expose_as: "pytest external renderer results" + reports: + junit: + - report-junit.xml + +evs-pytest-on-merge-request: + extends: + - .test-job-linux + - .rules-merge-request + stage: compare + needs: ["build-codec-linux-cmake", "codec-smoke-test"] + timeout: "10 minutes" + script: + - *print-common-info + - *merge-request-comparison-setup-codec + - *get-ivas-internal-ci-repo + - *overwrite-testv-with-internal-ones + + # some helper variables - "|| true" to prevent failures from grep not finding anything + - non_be_flag=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[evs[ -]*non[ -]*be\]") || true + - ref_using_main=$(echo $CI_MERGE_REQUEST_TITLE | grep -c --ignore-case "\[ref[ -]*using[ -]*main\]") || true + + ### If ref_using_main is not set, checkoug the source branch to use scripts and input from there + - if [ $ref_using_main == 0 ]; then git checkout $source_branch_commit_sha; fi + + ### prepare pytest + # create references + - python3 -m pytest tests/test_param_file.py -v --update_ref 1 -m create_ref --param_file scripts/config/self_test_evs.prm + + ### Run test using branch scripts and input + - if [ $ref_using_main == 1 ]; then git checkout $source_branch_commit_sha; fi + + ### run pytest for EVS cases + - exit_code=0 + - python3 -m pytest tests/test_param_file.py -v --param_file scripts/config/self_test_evs.prm --junit-xml=report-junit-evs.xml || exit_code=$? + - zero_errors=$(cat report-junit-evs.xml | grep -c 'errors="0"') || true + + - *merge-request-comparison-check + + allow_failure: + exit_codes: + - 123 + artifacts: + name: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + when: always + paths: + - report-junit-evs.xml + expose_as: "pytest evs results" + reports: + junit: + - report-junit-evs.xml + +clang-format-check: + extends: + - .test-job-linux + - .rules-merge-request + variables: + ARTIFACT_BASE_NAME: "mr-$CI_MERGE_REQUEST_IID--sha-$CI_COMMIT_SHORT_SHA--formatting-fix" + stage: validate + needs: [] + timeout: "5 minutes" + script: + # Set up variables. This can't be done in the "variables" section because variables are not expanded properly there + - PATCH_FILE_NAME="$ARTIFACT_BASE_NAME".patch + - > + INSTRUCTIONS_GITLAB="To fix formatting issues:\n + - download the diff patch available as artifact of this job\n + - unzip the artifact and place the patch file in the root directory of your local IVAS repo\n + - run: git apply $PATCH_FILE_NAME\n + - commit new changes" + - > + INSTRUCTIONS_README="To fix formatting issues:\n + - place the patch file in the root directory of your local IVAS repo\n + - run: git apply $PATCH_FILE_NAME\n + - commit new changes" + + - scripts/check-format.sh -af -p 8 || format_problems=$? + - if [ $format_problems == 0 ] ; then exit 0; fi + + - mkdir tmp-formatting-fix + - git diff > "tmp-formatting-fix/$PATCH_FILE_NAME" + + # Print instructions to job output + - echo -e "$INSTRUCTIONS_GITLAB" + + # Include readme in the artifact, in case someone misses the job printout (e.g. getting the artifact via MR interface) + - echo -e "$INSTRUCTIONS_README" > "tmp-formatting-fix/readme.txt" + + - exit $format_problems + artifacts: + paths: + - tmp-formatting-fix/ + when: on_failure + name: "$ARTIFACT_BASE_NAME" + expose_as: 'formatting patch' + allow_failure: true # TODO(sgi): Remove + + +# --------------------------------------------------------------- +# Test jobs for main branch +# --------------------------------------------------------------- + +# check bitexactness to EVS +# difference to forge: on the forge, this job runs only on pushes to main +# those are mirrored to our repo anyway, so no push-to-main triggers exist in +# our internal repo. Testing BE to EVS is probably only useful before moving a +# feature branch from internal to external repo. Therefore, this job internally +# runs on MR pipelines +be-2-evs-linux: + extends: + - .test-job-linux + # manual rules here to have .rules-main-push + run on MR + rules: + - if: $CI_PIPELINE_SOURCE == 'push' && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + # this is different from the forge repo -> allow manual run of the EVS-BE test + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + when: manual + allow_failure: true + tags: + - be-2-evs-temp + stage: test + needs: [ "build-codec-linux-cmake" ] + timeout: "20 minutes" + script: + - *print-common-info + + - mkdir build + - cd build + - cmake .. + - make -j + - cd .. + + # copy over to never change the testvector dir + - cp -r $EVS_BE_TEST_DIR ./evs_be_test + - cp build/IVAS_cod ./evs_be_test/bin/EVS_cod + - cp build/IVAS_dec ./evs_be_test/bin/EVS_dec + + - cd evs_be_test + - python3 ../ci/run_evs_be_test.py + +codec-comparison-on-main-push: + extends: + - .test-job-linux + - .rules-main-push + stage: compare + needs: [ "build-codec-linux-cmake" ] + timeout: "30 minutes" # To be revisited + script: + - *print-common-info + - latest_commit=$(git rev-parse HEAD) # Latest commit + - *get-previous-merge-commit-sha # Stored in previous_merge_commit shell variable now + - echo "Comparing changes from $previous_merge_commit to $latest_commit" + - git --no-pager diff --stat $previous_merge_commit..$latest_commit + + # Rest is more or less placeholder adapted from MR self test. This should be replaced with more complex tests. + + ### build test binaries, initial clean for paranoia reasons + - make clean + - mkdir build + - cd build + - cmake .. + - make -j + - mv IVAS_cod ../IVAS_cod_test + - mv IVAS_dec ../IVAS_dec_test + - cd .. + - rm -rf build/* + + ### compare to the previous merge commit in the main branch + - git fetch origin main + - git checkout $previous_merge_commit + + ### build reference binaries + - cd build + - cmake .. + - make -j + - mv IVAS_cod ../IVAS_cod_ref + - mv IVAS_dec ../IVAS_dec_ref + - cd .. + + ### re-checkout the latest commit in the main branch + - git checkout $latest_commit + + # helper variable - "|| true" to prevent failures from grep not finding anything + - non_be_flag=$(echo $CI_COMMIT_MESSAGE | grep -c --ignore-case "\[non[ -]*be\]") || true + + ### prepare pytest + # create short test vectors + - python3 tests/create_short_testvectors.py + # rename test binaries back + - mv IVAS_cod_test IVAS_cod + - mv IVAS_dec_test IVAS_dec + # create references + - python3 -m pytest tests -v --update_ref 1 -m create_ref + - python3 -m pytest tests -v --update_ref 1 -m create_ref_part2 + + ### run pytest + - exit_code=0 + - python3 -m pytest tests -v --junit-xml=report-junit.xml || exit_code=$? + - if [ $exit_code -eq 1 ] && [ $non_be_flag == 0 ]; then echo "pytest run had failures and non-BE flag not present"; exit $EXIT_CODE_FAIL; fi + - zero_errors=$(cat report-junit.xml | grep -c 'errors="0"') || true + - if [ $exit_code -eq 1 ] && [ $zero_errors == 1 ]; then echo "pytest run had failures, but no errors and non-BE flag present"; exit $EXIT_CODE_NON_BE; fi + - if [ $exit_code -ne 0 ]; then echo "pytest run had errors"; exit $EXIT_CODE_FAIL; fi; + allow_failure: + exit_codes: + - 123 + artifacts: + name: "main-push--sha-$CI_COMMIT_SHORT_SHA--stage-$CI_JOB_STAGE--results" + when: always + paths: + - report-junit.xml + expose_as: 'Results of comparison to previous merge commit' + reports: + junit: report-junit.xml + + +# --------------------------------------------------------------- +# Scheduled jobs on main +# --------------------------------------------------------------- +.sanitizer-test-template: + extends: + - .test-job-linux + tags: + - sanitizer_test_main + stage: test + artifacts: + name: "$CI_JOB_NAME--main--sha-$CI_COMMIT_SHORT_SHA" + when: always + paths: + - ep_015.g192 + - ./LOGS_PLC + - ./LOGS_noPLC + +sanitizer-test-mono: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MONO + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py mono mono --tests $SANITIZER_TESTS + +sanitizer-test-stereo: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_STEREO + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py stereo $OUT_FORMATS_CHANNEL_BASED --tests $SANITIZER_TESTS + +sanitizer-test-stereodmxevs: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_STEREODMXEVS + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py StereoDmxEVS mono --tests $SANITIZER_TESTS + +sanitizer-test-ism1: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_ISM1 + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py ISM1 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL EXT --tests $SANITIZER_TESTS + +sanitizer-test-ism2: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_ISM2 + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py ISM2 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL EXT --tests $SANITIZER_TESTS + +sanitizer-test-ism3: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_ISM3 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py ISM3 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL EXT --tests $SANITIZER_TESTS + +sanitizer-test-ism4: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_ISM4 + timeout: "4 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py ISM4 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL EXT --tests $SANITIZER_TESTS + +sanitizer-test-masa: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MASA + timeout: "2 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py MASA $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL EXT --tests $SANITIZER_TESTS + +sanitizer-test-mc-5_1: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MC51 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py 5_1 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-mc-5_1_2: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MC512 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py 5_1_2 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-mc-5_1_4: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MC514 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py 5_1_4 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-mc-7_1: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MC71 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py 7_1 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-mc-7_1_4: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_MC714 + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py 7_1_4 $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-sba: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_SBA + timeout: "4 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py SBA $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + +sanitizer-test-planarsba: + extends: .sanitizer-test-template + rules: + - if: $SANITIZER_TEST_PLANARSBA + timeout: "3 hours" + script: + - *get-ivas-internal-ci-repo + - *get-internal-ltv-signals + - ls -altr $LTV_DIR + - ls -altr + - cat scripts/config/ci_linux_ltv.json + - python3 ci/run_scheduled_sanitizer_test.py PlanarSBA $OUT_FORMATS_CHANNEL_BASED $OUT_FORMATS_SCENE_BASED $OUT_FORMATS_BINAURAL --tests $SANITIZER_TESTS + + +# GCOV/LCOV coverage analysis of self_test suite +coverage-test-on-main-scheduled: + extends: + - .test-job-linux-needs-internal-testv-dir + - .rules-main-scheduled + tags: + - coverage-test + stage: test + rules: + # only run in scheduled pipeline that passes this env vars + - if: $COVERAGE_TEST + script: + - *print-common-info + - make GCOV=1 -j + - python3 tests/create_short_testvectors.py + - python3 -m pytest tests -v -n 0 --update_ref 1 -m create_ref --ref_encoder_path ./IVAS_cod --ref_decoder_path ./IVAS_dec + - python3 -m pytest tests -v -n 0 --update_ref 1 -m create_ref_part2 --ref_encoder_path ./IVAS_cod --ref_decoder_path ./IVAS_dec + - python3 -m pytest tests/test_param_file.py -v -n 0 --update_ref 1 -m create_ref --param_file scripts/config/self_test_evs.prm --ref_encoder_path ./IVAS_cod --ref_decoder_path ./IVAS_dec + - lcov -c -d obj -o coverage.info + - genhtml coverage.info -o coverage + artifacts: + name: "main-coverage-sha-$CI_COMMIT_SHORT_SHA" + when: always + paths: + - coverage.info + - coverage + +# --------------------------------------------------------------- +# FhG internal - mirroring +# --------------------------------------------------------------- + +# Pull state of a branch on 3GPP repo, push to a mirror repo +.mirror-update: + extends: .test-job-linux + tags: + - host::r10499 + script: + # Set up git LFS for mirroring (see: https://github.com/git-lfs/git-lfs/issues/1762) + - git lfs install --skip-smudge --local + + # Select target branch: + # * if mirroring without testing, push to $CI_COMMIT_BRANCH at mirroring-pre-test stage + # * if mirroring with testing, push to: + # * $CI_COMMIT_BRANCH-mirror-untested at mirroring-pre-test stage + # * $CI_COMMIT_BRANCH at mirroring-post-test stage + - MIRROR_TARGET_BRANCH=$CI_COMMIT_BRANCH + - if [[ $MIRROR_TESTING == 'true' && $CI_JOB_STAGE == 'mirroring-pre-test' ]]; then MIRROR_TARGET_BRANCH="${CI_COMMIT_BRANCH}-mirror-untested"; fi + + # Check out or create mirror target branch - by default the runner checks out by commit hash, which results in detached head state + - git checkout -B $MIRROR_TARGET_BRANCH + + # Pull commits from upstream + - git pull --ff-only $UPSTREAM_URL $MIRROR_SOURCE_BRANCH + - git lfs fetch --all $UPSTREAM_URL $MIRROR_SOURCE_BRANCH + + # Push to mirror. Option `-o ci.skip` tells GitLab to skip CI for the pushed commits (testing already done in current pipeline if enabled) + - git push -o ci.skip "https://${GITLAB_USER_LOGIN}:${MIRROR_ACCESS_TOKEN}@${CI_REPOSITORY_URL#*@}" "HEAD:${MIRROR_TARGET_BRANCH}" + +mirror-update-untested: + rules: + - if: $MIRROR_ACCESS_TOKEN + extends: + - .mirror-update + stage: mirroring-pre-test + +mirror-update-tested: + rules: + - if: $MIRROR_ACCESS_TOKEN && $MIRROR_TESTING == 'true' + extends: + - .mirror-update + stage: mirroring-post-test + + +# --------------------------------------------------------------- +# FhG internal - tests +# --------------------------------------------------------------- + +build-codec-debug-windows-vs2017: + extends: + - .rules-basis + tags: + - os::windows + stage: build + script: + - $ENV:PATH + - MSBuild.exe .\Workspace_msvc\Workspace_msvc.sln /property:Configuration=Debug | tee $BUILD_OUTPUT + - python ci/check_for_warnings.py $BUILD_OUTPUT + allow_failure: + exit_codes: 123 + +build-codec-release-windows-vs2017: + extends: + - .rules-basis + tags: + - os::windows + stage: build + script: + - $ENV:PATH + - MSBuild.exe .\Workspace_msvc\Workspace_msvc.sln /property:Configuration=Release | tee $BUILD_OUTPUT + - python ci/check_for_warnings.py $BUILD_OUTPUT + allow_failure: + exit_codes: 123 \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..192aece8ecb31a3c9b02af94b54b4f111b7f1c6b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "scripts/razel/ivas_razel_runner"] + path = scripts/razel/ivas_razel_runner + url = ../../sgi/ivas-razel-runner.git + branch = rend diff --git a/apps/decoder.c b/apps/decoder.c index 74aa3d73765d78cac931e48c8379941f2e447fea..63bc7f5d5bb7368901ea44bbad7c91a5f098e432 100644 --- a/apps/decoder.c +++ b/apps/decoder.c @@ -96,6 +96,10 @@ static #define VARIABLE_SPEED_FETCH_FRAMESIZE_MS 20 #endif #define JBM_FRONTEND_FETCH_FRAMESIZE_MS 20 +#ifdef API_5MS +#define HEADROTATION_FETCH_FRAMESIZE_MS 5 +#define DEFAULT_FETCH_FRAMESIZE_MS 20 +#endif typedef struct { @@ -137,7 +141,9 @@ typedef struct char *outputMdFilename; #endif IVAS_DEC_COMPLEXITY_LEVEL complexityLevel; - +#ifdef API_5MS + bool tsmEnabled; +#endif #ifdef DEBUGGING IVAS_DEC_FORCED_REND_MODE forcedRendMode; #ifdef DEBUG_FOA_AGC @@ -147,7 +153,9 @@ typedef struct bool noBadFrameDelay; #endif #ifdef VARIABLE_SPEED_DECODING +#ifndef API_5MS bool variableSpeedMode; +#endif bool tsmScaleFileEnabled; char *tsmScaleFileName; uint16_t tsmScale; @@ -433,7 +441,11 @@ int main( arg.enableHeadRotation = true; } #endif +#ifdef API_5MS + if ( ( error = IVAS_DEC_Configure( hIvasDec, arg.output_Fs, arg.outputFormat, arg.tsmEnabled, arg.customLsOutputEnabled, arg.hrtfReaderEnabled, arg.enableHeadRotation, arg.enableExternalOrientation, arg.orientation_tracking, arg.renderConfigEnabled, arg.Opt_non_diegetic_pan, arg.non_diegetic_pan_gain, arg.delayCompensationEnabled ) ) != IVAS_ERR_OK ) +#else if ( ( error = IVAS_DEC_Configure( hIvasDec, arg.output_Fs, arg.outputFormat, arg.customLsOutputEnabled, arg.hrtfReaderEnabled, arg.enableHeadRotation, arg.enableExternalOrientation, arg.orientation_tracking, arg.renderConfigEnabled, arg.Opt_non_diegetic_pan, arg.non_diegetic_pan_gain, arg.delayCompensationEnabled ) ) != IVAS_ERR_OK ) +#endif { fprintf( stderr, "\nConfigure failed: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -445,16 +457,21 @@ int main( if ( arg.voipMode ) { -#ifdef VARIABLE_SPEED_DECODING - if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, IVAS_DEC_VOIP_MODE_VOIP, 100, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) +#ifdef API_5MS + if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) #else +#ifndef VARIABLE_SPEED_DECODING if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_DEC_EnableVoIP( hIvasDec, IVAS_DEC_VOIP_MODE_VOIP, 100, 60, arg.inputFormat ) ) != IVAS_ERR_OK ) +#endif #endif { fprintf( stderr, "\nCould not enable VOIP: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } } +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING else if ( arg.variableSpeedMode ) { @@ -465,6 +482,7 @@ int main( } } #endif +#endif #ifdef DEBUGGING /*-----------------------------------------------------------------* @@ -498,7 +516,11 @@ int main( IVAS_DEC_PrintConfigWithBitstream( hIvasDec, arg.quietModeEnabled, bit_stream, num_bits ); #ifdef VARIABLE_SPEED_DECODING +#ifdef API_5MS + if ( arg.tsmEnabled ) +#else if ( arg.variableSpeedMode ) +#endif { if ( arg.tsmScaleFileEnabled ) { @@ -686,6 +708,7 @@ int main( { error = decodeVoIP( arg, hBsReader, hIvasDec ); } +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING else if ( arg.variableSpeedMode ) { @@ -693,6 +716,7 @@ int main( externalOrientationFileReader, refRotReader, referenceVectorReader, hIvasDec ); } +#endif #endif else { @@ -947,10 +971,14 @@ static bool parseCmdlIVAS_dec( arg->inputFormat = IVAS_DEC_INPUT_FORMAT_G192; arg->Opt_non_diegetic_pan = 0; arg->non_diegetic_pan_gain = 0.f; - +#ifdef API_5MS + arg->tsmEnabled = false; +#endif #ifdef DEBUGGING #ifdef VARIABLE_SPEED_DECODING +#ifndef API_5MS arg->variableSpeedMode = false; +#endif arg->tsmScale = 100; arg->tsmScaleFileEnabled = false; arg->tsmScaleFileName = NULL; @@ -1099,7 +1127,11 @@ static bool parseCmdlIVAS_dec( { i++; int32_t tmp = 100; +#ifdef API_5MS + arg->tsmEnabled = true; +#else arg->variableSpeedMode = true; +#endif if ( i < argc - 3 ) { if ( !is_digits_only( argv[i] ) ) @@ -1760,7 +1792,7 @@ static ivas_error initOnFirstGoodFrame( * * Read G.192 bitstream and decode in regular decoder *---------------------------------------------------------------------*/ - +#ifdef API_5MS static ivas_error decodeG192( DecArguments arg, BS_READER_HANDLE hBsReader, @@ -1788,25 +1820,62 @@ static ivas_error decodeG192( int16_t numInitialBadFrames = 0; /* Number of bad frames received until first good frame is decoded */ int16_t nOutChannels = 0; int16_t delayNumSamples = -1; - int16_t delayNumSamples_orig[3]; /* stores: overall delay, dec+rend delay, and binauralization delay */ + int16_t delayNumSamples_orig[3]; int16_t nOutSamples = 0; int32_t delayTimeScale = 0; ivas_error error = IVAS_ERR_UNKNOWN; uint16_t numObj = 0; IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN; - IVAS_VECTOR3 Pos[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + uint16_t nSamplesAvailableNext; + bool needNewFrame; + int16_t nSamplesRendered, nSamplesRendered_loop, nSamplesToRender; +#ifdef DEBUGGING +#ifdef VARIABLE_SPEED_DECODING + TsmScaleFileReader *tsmScaleFileReader = NULL; + int16_t scale; +#endif +#endif + IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS]; + IVAS_VECTOR3 Pos; + int16_t vec_pos_update, vec_pos_len; #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_BITS splitRendBits; SplitFileReadWrite *hSplitRendFileReadWrite; #endif - IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS]; for ( i = 0; i < IVAS_MAX_NUM_OBJECTS; ++i ) { ismWriters[i] = NULL; } + /* we always start with needing a new frame */ + needNewFrame = true; + +#ifdef DEBUGGING +#ifdef VARIABLE_SPEED_DECODING + /*------------------------------------------------------------------------------------------* + * Open TSM scale file or set global TSM scale + *------------------------------------------------------------------------------------------*/ + + if ( arg.tsmEnabled ) + { + if ( arg.tsmScaleFileEnabled ) + { + if ( ( tsmScaleFileReader = TsmScaleFileReader_open( arg.tsmScaleFileName ) ) == NULL ) + { + fprintf( stderr, "\nError: Can't open TSM scale file %s \n\n", arg.tsmScaleFileName ); + goto cleanup; + } + } + else + { + IVAS_DEC_VoIP_SetScale( hIvasDec, arg.tsmScale, arg.tsmScale ); + } + } +#endif +#endif + if ( !arg.quietModeEnabled ) { fprintf( stdout, "\n------ Running the decoder ------\n\n" ); @@ -1823,6 +1892,19 @@ static ivas_error decodeG192( reset_stack(); reset_wmops(); #endif + nSamplesAvailableNext = 0; + + vec_pos_update = 0; + if ( arg.enableHeadRotation ) + { + nOutSamples = (int16_t) ( arg.output_Fs / 1000 * HEADROTATION_FETCH_FRAMESIZE_MS ); + vec_pos_len = IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; + } + else + { + nOutSamples = (int16_t) ( arg.output_Fs / 1000 * DEFAULT_FETCH_FRAMESIZE_MS ); + vec_pos_len = 1; + } #ifdef SPLIT_REND_WITH_HEAD_ROT splitRendBits.bits_buf = splitRendBitsBuf; @@ -1841,42 +1923,10 @@ static ivas_error decodeG192( while ( 1 ) { - /* Read next frame */ - if ( ( error = BS_Reader_ReadFrame_short( hBsReader, bit_stream, &num_bits, &bfi ) ) != IVAS_ERR_OK ) - { - if ( error == IVAS_ERR_END_OF_FILE ) - { - break; - } - fprintf( stderr, "\nError: input bitstream file couldn't be read: %s \n\n", arg.inputBitstreamFilename ); - goto cleanup; - } - -#ifdef DEBUGGING - /* Random FEC simulation */ - if ( arg.FER > 0.0f ) - { - float ftmp = (float) app_own_random( &fec_seed ) + 32768.0f; - if ( ftmp <= arg.FER / 100.0f * 65535.0f ) - { - bfi = 1; - } - else - { - bfi = 0; - } - } -#endif - - /* Feed into decoder */ - if ( ( error = IVAS_DEC_FeedFrame_Serial( hIvasDec, bit_stream, num_bits, bfi ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError: could not feed frame to decoder: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); - goto cleanup; - } + /* Read next frame if not enough samples availble */ /* reference vector */ - if ( arg.enableReferenceVectorTracking ) + if ( arg.enableReferenceVectorTracking && vec_pos_update == 0 ) { IVAS_VECTOR3 listenerPosition, referencePosition; if ( ( error = Vector3PairFileReader_read( referenceVectorReader, &listenerPosition, &referencePosition ) ) != IVAS_ERR_OK ) @@ -1891,14 +1941,14 @@ static ivas_error decodeG192( goto cleanup; } } + /* Reference rotation */ - if ( arg.enableReferenceRotation ) + if ( arg.enableReferenceRotation && vec_pos_update == 0 ) { IVAS_QUATERNION quaternion; if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), - RotationFileReader_getFilePath( refRotReader ) ); + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), RotationFileReader_getFilePath( refRotReader ) ); goto cleanup; } @@ -1908,39 +1958,34 @@ static ivas_error decodeG192( goto cleanup; } } + /* Head-tracking input simulation */ if ( arg.enableHeadRotation ) { - IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION Quaternion; #ifdef SPLIT_REND_WITH_HEAD_ROT if ( headRotReader == NULL ) { - for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) - { - Quaternions[i].w = -3.0f; - Quaternions[i].x = 0.0f; - Quaternions[i].y = 0.0f; - Quaternions[i].z = 0.0f; - } + Quaternion.w = -3.0f; + Quaternion.x = 0.0f; + Quaternion.y = 0.0f; + Quaternion.z = 0.0f; } else { #endif - for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + if ( ( error = HeadRotationFileReading( headRotReader, &Quaternion, &Pos ) ) != IVAS_ERR_OK ) { - if ( ( error = HeadRotationFileReading( headRotReader, &Quaternions[i], &Pos[i] ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), - RotationFileReader_getFilePath( headRotReader ) ); - goto cleanup; - } + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), RotationFileReader_getFilePath( headRotReader ) ); + goto cleanup; } #ifdef SPLIT_REND_WITH_HEAD_ROT } #endif - if ( ( error = IVAS_DEC_FeedHeadTrackData( hIvasDec, Quaternions, Pos + + if ( ( error = IVAS_DEC_FeedHeadTrackData( hIvasDec, Quaternion, Pos #ifdef SPLIT_REND_WITH_HEAD_ROT , DEFAULT_AXIS @@ -1954,40 +1999,116 @@ static ivas_error decodeG192( if ( arg.enableExternalOrientation ) { - IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; - int8_t enableHeadRotation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; - int8_t enableExternalOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; - int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; - int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION Quaternion; + int8_t enableHeadRotation; + int8_t enableExternalOrientation; + int8_t enableRotationInterpolation; + int16_t numFramesToTargetOrientation; - for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) - { - if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternions[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), - RotationFileReader_getFilePath( externalOrientationFileReader ) ); - goto cleanup; - } + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternion, &enableHeadRotation, &enableExternalOrientation, &enableRotationInterpolation, &numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( externalOrientationFileReader ) ); + goto cleanup; } - if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternions, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + + if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternion, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation * vec_pos_len ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nIVAS_DEC_FeedExternalOrientationData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; } } - /* Run decoder for one frame (get rendered output) */ - if ( ( error = IVAS_DEC_GetSamples( hIvasDec, pcmBuf, &nOutSamples + /* decode and get samples */ + nSamplesRendered = 0; + nSamplesToRender = nOutSamples; + do + { + if ( needNewFrame ) + { +#ifdef DEBUGGING +#ifdef VARIABLE_SPEED_DECODING + if ( arg.tsmScaleFileEnabled ) + { + if ( ( error = TsmScaleFileReader_readScale( tsmScaleFileReader, &scale ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: input bitstream file couldn't be read: %s \n\n", arg.inputBitstreamFilename ); + goto cleanup; + } + IVAS_DEC_VoIP_SetScale( hIvasDec, scale, scale ); + } +#endif +#endif + + if ( ( error = BS_Reader_ReadFrame_short( hBsReader, bit_stream, &num_bits, &bfi ) ) != IVAS_ERR_OK ) + { + if ( error == IVAS_ERR_END_OF_FILE ) + { + break; + } + fprintf( stderr, "\nError: input bitstream file couldn't be read: %s \n\n", arg.inputBitstreamFilename ); + goto cleanup; + } + +#ifdef DEBUGGING + /* Random FEC simulation */ + if ( arg.FER > 0.0f ) + { + float ftmp = (float) app_own_random( &fec_seed ) + 32768.0f; + if ( ftmp <= arg.FER / 100.0f * 65535.0f ) + { + bfi = 1; + } + else + { + bfi = 0; + } + } +#endif + + /* Feed into decoder */ + if ( ( error = IVAS_DEC_FeedFrame_Serial( hIvasDec, bit_stream, num_bits, bfi ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: could not feed frame to decoder: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + #ifdef SPLIT_REND_WITH_HEAD_ROT - , - &splitRendBits + if ( arg.outputFormat == IVAS_DEC_OUTPUT_SPLIT_BINAURAL_CODED || arg.outputFormat == IVAS_DEC_OUTPUT_SPLIT_BINAURAL_PCM ) + { + error = IVAS_DEC_GetSplitBinaural(hIvasDec, &splitRendBits, &nSamplesRendered_loop, &needNewFrame ); + nSamplesRendered += nSamplesRendered_loop; + nSamplesToRender -= nSamplesRendered_loop; + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetSplitBinaural: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + else + { #endif - ) ) != IVAS_ERR_OK ) + error = IVAS_DEC_GetSamples( hIvasDec, nSamplesToRender, pcmBuf + nOutChannels * nSamplesRendered, &nSamplesRendered_loop, &needNewFrame ); + nSamplesRendered += nSamplesRendered_loop; + nSamplesToRender -= nSamplesRendered_loop; + if ( error != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_GetSamples: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } +#ifdef SPLIT_REND_WITH_HEAD_ROT + } +#endif + + + } while ( nSamplesRendered < nOutSamples && error == IVAS_ERR_OK ); + + if ( error == IVAS_ERR_END_OF_FILE ) { - fprintf( stderr, "\nError: could not get samples from decoder: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); - goto cleanup; + break; } /* Continue checking for first good frame until it is found */ @@ -2020,7 +2141,7 @@ static ivas_error decodeG192( , &hSplitRendFileReadWrite #endif - ); + ); if ( error != IVAS_ERR_OK ) { goto cleanup; @@ -2042,7 +2163,7 @@ static ivas_error decodeG192( splitRendBits.codec, splitRendBits.pose_correction ) != IVAS_ERR_OK ) { fprintf( stderr, "\nUnable to write to bitstream file!\n" ); - exit( -1 ); + goto cleanup; } } else @@ -2053,7 +2174,7 @@ static ivas_error decodeG192( splitRendBits.codec, splitRendBits.pose_correction ) != IVAS_ERR_OK ) { fprintf( stderr, "\nUnable to write to bitstream file!\n" ); - exit( -1 ); + goto cleanup; } } #endif @@ -2075,7 +2196,7 @@ static ivas_error decodeG192( #endif } - /* Write ISM metadata to external file(s) */ + /* Write ISm metadata to external file(s) */ if ( decodedGoodFrame && arg.outputFormat == IVAS_DEC_OUTPUT_EXT ) { if ( bsFormat == IVAS_DEC_BS_OBJ ) @@ -2125,6 +2246,7 @@ static ivas_error decodeG192( } frame++; + vec_pos_update = ( vec_pos_update + 1 ) % vec_pos_len; if ( !arg.quietModeEnabled ) { fprintf( stdout, "%-8d\b\b\b\b\b\b\b\b", frame ); @@ -2136,44 +2258,647 @@ static ivas_error decodeG192( #endif } #ifdef WMOPS - update_mem(); update_wmops(); +#ifdef MEM_COUNT_DETAILS + export_mem( "mem_analysis.csv" ); #endif - } - - /*------------------------------------------------------------------------------------------* - * Add zeros at the end to have equal length of synthesized signals - *------------------------------------------------------------------------------------------*/ - - memset( pcmBuf, 0, delayNumSamples_orig[0] * nOutChannels * sizeof( int16_t ) ); - -#ifdef SPLIT_REND_WITH_HEAD_ROT - if ( afWriter != NULL ) - { #endif - if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, delayNumSamples_orig[0] * nOutChannels ) ) != IVAS_ERR_OK ) - { - fprintf( stderr, "\nError writing output file: %s\n", ivas_error_to_string( error ) ); - goto cleanup; - } -#ifdef SPLIT_REND_WITH_HEAD_ROT } -#endif + /*------------------------------------------------------------------------------------------* - * Printouts after decoding has finished + * Flush what is still left in the VoIP Buffers.... *------------------------------------------------------------------------------------------*/ - if ( !arg.quietModeEnabled ) + while ( nSamplesAvailableNext > 0 ) { - printf( "\n\nDecoder+renderer delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[1] / (float) delayTimeScale, delayNumSamples_orig[1], delayTimeScale ); + int16_t nSamplesFlushed; - if ( delayNumSamples_orig[2] > 0 ) - { - printf( "HRIR/BRIR delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[2] / (float) delayTimeScale, delayNumSamples_orig[2], delayTimeScale ); - printf( "Total delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * ( delayNumSamples_orig[1] + delayNumSamples_orig[2] ) / (float) delayTimeScale, delayNumSamples_orig[1] + delayNumSamples_orig[2], delayTimeScale ); - } - } + /* Feed into decoder */ + + /* reference vector */ + if ( arg.enableReferenceVectorTracking ) + { + IVAS_VECTOR3 listenerPosition, referencePosition; + if ( ( error = Vector3PairFileReader_read( referenceVectorReader, &listenerPosition, &referencePosition ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading listener and reference positions from %s\n", IVAS_DEC_GetErrorMessage( error ), Vector3PairFileReader_getFilePath( referenceVectorReader ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_FeedRefVectorData( hIvasDec, listenerPosition, referencePosition ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedRefVectorData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + /* Reference rotation */ + if ( arg.enableReferenceRotation ) + { + IVAS_QUATERNION quaternion; + if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), RotationFileReader_getFilePath( refRotReader ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_FeedRefRotData( hIvasDec, quaternion ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedRefRotData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + /* Head-tracking input simulation */ + if ( arg.enableHeadRotation ) + { + IVAS_QUATERNION Quaternion; + + + if ( ( error = HeadRotationFileReading( headRotReader, &Quaternion, &Pos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), RotationFileReader_getFilePath( headRotReader ) ); + goto cleanup; + } + + + if ( ( error = IVAS_DEC_FeedHeadTrackData( hIvasDec, Quaternion, Pos +#ifdef SPLIT_REND_WITH_HEAD_ROT + ,DEFAULT_AXIS +#endif + ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedHeadTrackData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + /* decode and get samples */ + if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, pcmBuf, &nSamplesFlushed ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_VoIP_Flush: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* Write current frame */ + if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, nSamplesFlushed * nOutChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nOutput audio file writer error\n" ); + goto cleanup; + } + + /* Write ISm metadata to external file(s) */ + if ( decodedGoodFrame && arg.outputFormat == IVAS_DEC_OUTPUT_EXT ) + { + if ( bsFormat == IVAS_DEC_BS_OBJ ) + { + if ( ( error = IVAS_DEC_GetNumObjects( hIvasDec, &numObj ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetNumObjects: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + for ( i = 0; i < numObj; ++i ) + { + IVAS_ISM_METADATA IsmMetadata; + + if ( ( error = IVAS_DEC_GetObjectMetadata( hIvasDec, &IsmMetadata, 0, i ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetObjectMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( IsmFileWriter_writeFrame( IsmMetadata, ismWriters[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing ISM metadata to file %s\n", IsmFileWriter_getFilePath( ismWriters[i] ) ); + goto cleanup; + } + } + } + else if ( bsFormat == IVAS_DEC_BS_MASA ) + { + MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef FIX_470_MASA_JBM_EXT + if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 0 ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); + goto cleanup; + } + } + } + + frame++; + if ( !arg.quietModeEnabled ) + { + fprintf( stdout, "%-8d\b\b\b\b\b\b\b\b", frame ); +#ifdef DEBUGGING + if ( IVAS_DEC_GetBerDetectFlag( hIvasDec ) ) + { + fprintf( stdout, "\n Decoding error: BER detected in frame %d !!!!!\n", frame - 1 ); + } +#endif + } + } + + /*------------------------------------------------------------------------------------------* + * Printouts after decoding has finished + *------------------------------------------------------------------------------------------*/ + + if ( !arg.quietModeEnabled ) + { + printf( "\n\nDecoder+renderer delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[1] / (float) delayTimeScale, delayNumSamples_orig[1], delayTimeScale ); + + if ( delayNumSamples_orig[2] > 0 ) + { + printf( "HRIR/BRIR delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[2] / (float) delayTimeScale, delayNumSamples_orig[2], delayTimeScale ); + printf( "Total delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * ( delayNumSamples_orig[1] + delayNumSamples_orig[2] ) / (float) delayTimeScale, delayNumSamples_orig[1] + delayNumSamples_orig[2], delayTimeScale ); + } + } + + /* Print output metadata file name(s) */ + if ( arg.outputFormat == IVAS_DEC_OUTPUT_EXT ) + { + if ( bsFormat == IVAS_DEC_BS_OBJ ) + { + for ( i = 0; i < numObj; i++ ) + { + fprintf( stdout, "\nOutput metadata file: %s", IsmFileWriter_getFilePath( ismWriters[i] ) ); + } + fprintf( stdout, "\n" ); + } + else if ( bsFormat == IVAS_DEC_BS_MASA ) + { + fprintf( stdout, "\nOutput metadata file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); + } + } + + /* add zeros at the end to have equal length of synthesized signals */ + memset( pcmBuf, 0, delayNumSamples_orig[0] * nOutChannels * sizeof( int16_t ) ); +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( afWriter != NULL ) + { +#endif + if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, delayNumSamples_orig[0] * nOutChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing output file: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } +#ifdef SPLIT_REND_WITH_HEAD_ROT + } +#endif + + /*------------------------------------------------------------------------------------------* + * Close files and deallocate resources + *------------------------------------------------------------------------------------------*/ + + decodingFailed = false; /* This will stay set to true if cleanup is reached via a goto due to an error */ + +cleanup: + +#ifdef SPLIT_REND_WITH_HEAD_ROT + split_rend_reader_writer_close( &hSplitRendFileReadWrite ); +#endif + AudioFileWriter_close( &afWriter ); + MasaFileWriter_close( &masaWriter ); +#ifdef DEBUGGING +#ifdef VARIABLE_SPEED_DECODING + TsmScaleFileReader_close( &tsmScaleFileReader ); +#endif +#endif + for ( i = 0; i < IVAS_MAX_NUM_OBJECTS; i++ ) + { + IsmFileWriter_close( &ismWriters[i] ); + } + + if ( decodingFailed && error == IVAS_ERR_OK ) + { + return IVAS_ERR_UNKNOWN; + } + + return error; +} +#else +static ivas_error decodeG192( + DecArguments arg, + BS_READER_HANDLE hBsReader, + RotFileReader *headRotReader, + RotFileReader *externalOrientationFileReader, + RotFileReader *refRotReader, + Vector3PairFileReader *referenceVectorReader, +#ifdef SPLIT_REND_WITH_HEAD_ROT + uint8_t *splitRendBitsBuf, +#endif + IVAS_DEC_HANDLE hIvasDec, + int16_t *pcmBuf ) + +{ + bool decodingFailed = true; /* Assume failure until cleanup is reached without errors */ + uint16_t bit_stream[IVAS_MAX_BITS_PER_FRAME + 4 * 8]; + int16_t i, num_bits; + int16_t bfi = 0; +#ifdef DEBUGGING + int16_t fec_seed = 12558; /* FEC_SEED */ +#endif + AudioFileWriter *afWriter = NULL; + MasaFileWriter *masaWriter = NULL; + bool decodedGoodFrame = false; + int16_t numInitialBadFrames = 0; /* Number of bad frames received until first good frame is decoded */ + int16_t nOutChannels = 0; + int16_t delayNumSamples = -1; + int16_t delayNumSamples_orig[3]; /* stores: overall delay, dec+rend delay, and binauralization delay */ + int16_t nOutSamples = 0; + int32_t delayTimeScale = 0; + ivas_error error = IVAS_ERR_UNKNOWN; + uint16_t numObj = 0; + IVAS_DEC_BS_FORMAT bsFormat = IVAS_DEC_BS_UNKOWN; + IVAS_VECTOR3 Pos[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + +#ifdef SPLIT_REND_WITH_HEAD_ROT + IVAS_SPLIT_REND_BITS splitRendBits; + SplitFileReadWrite *hSplitRendFileReadWrite; +#endif + + IsmFileWriter *ismWriters[IVAS_MAX_NUM_OBJECTS]; + for ( i = 0; i < IVAS_MAX_NUM_OBJECTS; ++i ) + { + ismWriters[i] = NULL; + } + + if ( !arg.quietModeEnabled ) + { + fprintf( stdout, "\n------ Running the decoder ------\n\n" ); + fprintf( stdout, "Frames processed: " ); + } + else + { + fprintf( stdout, "\n-- Start the decoder (quiet mode) --\n\n" ); + } + + delayNumSamples_orig[0] = -1; + +#ifdef WMOPS + reset_stack(); + reset_wmops(); +#endif + +#ifdef SPLIT_REND_WITH_HEAD_ROT + splitRendBits.bits_buf = splitRendBitsBuf; + splitRendBits.bits_read = 0; + splitRendBits.bits_written = 0; + splitRendBits.buf_len = MAX_SPLIT_REND_BITS_BUFFER_SIZE_IN_BYTES; + hSplitRendFileReadWrite = NULL; +#endif + + /*------------------------------------------------------------------------------------------* + * Loop for every packet (frame) of bitstream data + * - Read the bitstream packet + * - Run the decoder + * - Write the synthesized signal into output file + *------------------------------------------------------------------------------------------*/ + + while ( 1 ) + { + /* Read next frame */ + if ( ( error = BS_Reader_ReadFrame_short( hBsReader, bit_stream, &num_bits, &bfi ) ) != IVAS_ERR_OK ) + { + if ( error == IVAS_ERR_END_OF_FILE ) + { + break; + } + fprintf( stderr, "\nError: input bitstream file couldn't be read: %s \n\n", arg.inputBitstreamFilename ); + goto cleanup; + } + +#ifdef DEBUGGING + /* Random FEC simulation */ + if ( arg.FER > 0.0f ) + { + float ftmp = (float) app_own_random( &fec_seed ) + 32768.0f; + if ( ftmp <= arg.FER / 100.0f * 65535.0f ) + { + bfi = 1; + } + else + { + bfi = 0; + } + } +#endif + + /* Feed into decoder */ + if ( ( error = IVAS_DEC_FeedFrame_Serial( hIvasDec, bit_stream, num_bits, bfi ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: could not feed frame to decoder: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* reference vector */ + if ( arg.enableReferenceVectorTracking ) + { + IVAS_VECTOR3 listenerPosition, referencePosition; + if ( ( error = Vector3PairFileReader_read( referenceVectorReader, &listenerPosition, &referencePosition ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading listener and reference positions from %s\n", IVAS_DEC_GetErrorMessage( error ), Vector3PairFileReader_getFilePath( referenceVectorReader ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_FeedRefVectorData( hIvasDec, listenerPosition, referencePosition ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedRefVectorData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + /* Reference rotation */ + if ( arg.enableReferenceRotation ) + { + IVAS_QUATERNION quaternion; + if ( ( error = HeadRotationFileReading( refRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading reference rotation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( refRotReader ) ); + goto cleanup; + } + + if ( ( error = IVAS_DEC_FeedRefRotData( hIvasDec, quaternion ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedRefRotData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + /* Head-tracking input simulation */ + if ( arg.enableHeadRotation ) + { + IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( headRotReader == NULL ) + { + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + Quaternions[i].w = -3.0f; + Quaternions[i].x = 0.0f; + Quaternions[i].y = 0.0f; + Quaternions[i].z = 0.0f; + } + } + else + { +#endif + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + if ( ( error = HeadRotationFileReading( headRotReader, &Quaternions[i], &Pos[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading head orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( headRotReader ) ); + goto cleanup; + } + } +#ifdef SPLIT_REND_WITH_HEAD_ROT + } +#endif + + if ( ( error = IVAS_DEC_FeedHeadTrackData( hIvasDec, Quaternions, Pos +#ifdef SPLIT_REND_WITH_HEAD_ROT + , + DEFAULT_AXIS +#endif + ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedHeadTrackData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + if ( arg.enableExternalOrientation ) + { + IVAS_QUATERNION Quaternions[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableHeadRotation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableExternalOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int8_t enableRotationInterpolation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + int16_t numFramesToTargetOrientation[IVAS_MAX_PARAM_SPATIAL_SUBFRAMES]; + + for ( i = 0; i < IVAS_MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) + { + + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &Quaternions[i], &enableHeadRotation[i], &enableExternalOrientation[i], &enableRotationInterpolation[i], &numFramesToTargetOrientation[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError %s while reading external orientation from %s\n", IVAS_DEC_GetErrorMessage( error ), + RotationFileReader_getFilePath( externalOrientationFileReader ) ); + goto cleanup; + } + } + + if ( ( error = IVAS_DEC_FeedExternalOrientationData( hIvasDec, Quaternions, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nIVAS_DEC_FeedExternalOrientationData failed: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + } + + /* Run decoder for one frame (get rendered output) */ + if ( ( error = IVAS_DEC_GetSamples( hIvasDec, pcmBuf, &nOutSamples +#ifdef SPLIT_REND_WITH_HEAD_ROT + , + &splitRendBits +#endif + ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError: could not get samples from decoder: %s\n\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + /* Continue checking for first good frame until it is found */ + if ( !decodedGoodFrame ) + { + if ( ( error = IVAS_DEC_HasDecodedFirstGoodFrame( hIvasDec, &decodedGoodFrame ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_HasDecodedFirstGoodFrame, code: %d\n", error ); + goto cleanup; + } + + /* Once good frame decoded, catch up */ + if ( decodedGoodFrame ) + { + error = initOnFirstGoodFrame( + hIvasDec, + arg, + numInitialBadFrames, + nOutSamples, + delayNumSamples_orig, + &delayNumSamples, + &delayTimeScale, + &bsFormat, + &afWriter, + &masaWriter, + ismWriters, + &nOutChannels, + &numObj +#ifdef SPLIT_REND_WITH_HEAD_ROT + , + &hSplitRendFileReadWrite +#endif + ); + if ( error != IVAS_ERR_OK ) + { + goto cleanup; + } + } + else + { + ++numInitialBadFrames; + } + } + + /* Write current frame */ + if ( decodedGoodFrame ) + { +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( ( hSplitRendFileReadWrite != NULL ) && ( arg.outputFormat == IVAS_DEC_OUTPUT_SPLIT_BINAURAL_CODED ) ) + { + if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, splitRendBits.bits_buf, &splitRendBits.bits_read, &splitRendBits.bits_written, + splitRendBits.codec, splitRendBits.pose_correction ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to write to bitstream file!\n" ); + exit( -1 ); + } + } + else + { + if ( ( hSplitRendFileReadWrite != NULL ) && ( arg.outputFormat == IVAS_DEC_OUTPUT_SPLIT_BINAURAL_PCM ) ) + { + if ( split_rend_write_bitstream_to_file( hSplitRendFileReadWrite, splitRendBits.bits_buf, &splitRendBits.bits_read, &splitRendBits.bits_written, + splitRendBits.codec, splitRendBits.pose_correction ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nUnable to write to bitstream file!\n" ); + exit( -1 ); + } + } +#endif + if ( delayNumSamples < nOutSamples ) + { + if ( ( error = AudioFileWriter_write( afWriter, &pcmBuf[delayNumSamples * nOutChannels], nOutSamples * nOutChannels - ( delayNumSamples * nOutChannels ) ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nOutput audio file writer error\n" ); + goto cleanup; + } + delayNumSamples = 0; + } + else + { + delayNumSamples -= nOutSamples; + } +#ifdef SPLIT_REND_WITH_HEAD_ROT + } +#endif + } + + /* Write ISM metadata to external file(s) */ + if ( decodedGoodFrame && arg.outputFormat == IVAS_DEC_OUTPUT_EXT ) + { + if ( bsFormat == IVAS_DEC_BS_OBJ ) + { + if ( ( error = IVAS_DEC_GetNumObjects( hIvasDec, &numObj ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetNumObjects: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + for ( i = 0; i < numObj; ++i ) + { + IVAS_ISM_METADATA IsmMetadata; + + if ( ( error = IVAS_DEC_GetObjectMetadata( hIvasDec, &IsmMetadata, 0, i ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError in IVAS_DEC_GetObjectMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( IsmFileWriter_writeFrame( IsmMetadata, ismWriters[i] ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing ISM metadata to file %s\n", IsmFileWriter_getFilePath( ismWriters[i] ) ); + goto cleanup; + } + } + } + else if ( bsFormat == IVAS_DEC_BS_MASA ) + { + MASA_DECODER_EXT_OUT_META_HANDLE hMasaExtOutMeta; +#ifdef FIX_470_MASA_JBM_EXT + if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta, 0 ) ) != IVAS_ERR_OK ) +#else + if ( ( error = IVAS_DEC_GetMasaMetadata( hIvasDec, &hMasaExtOutMeta ) ) != IVAS_ERR_OK ) +#endif + { + fprintf( stderr, "\nError in IVAS_DEC_GetMasaMetadata: %s\n", IVAS_DEC_GetErrorMessage( error ) ); + goto cleanup; + } + + if ( ( error = MasaFileWriter_writeFrame( masaWriter, hMasaExtOutMeta ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing MASA metadata to file: %s\n", MasaFileWriter_getFilePath( masaWriter ) ); + goto cleanup; + } + } + } + + frame++; + if ( !arg.quietModeEnabled ) + { + fprintf( stdout, "%-8d\b\b\b\b\b\b\b\b", frame ); +#ifdef DEBUGGING + if ( IVAS_DEC_GetBerDetectFlag( hIvasDec ) ) + { + fprintf( stdout, "\n Decoding error: BER detected in frame %d !!!!!\n", frame - 1 ); + } +#endif + } +#ifdef WMOPS + update_mem(); + update_wmops(); +#endif + } + + /*------------------------------------------------------------------------------------------* + * Add zeros at the end to have equal length of synthesized signals + *------------------------------------------------------------------------------------------*/ + + memset( pcmBuf, 0, delayNumSamples_orig[0] * nOutChannels * sizeof( int16_t ) ); + +#ifdef SPLIT_REND_WITH_HEAD_ROT + if ( afWriter != NULL ) + { +#endif + if ( ( error = AudioFileWriter_write( afWriter, pcmBuf, delayNumSamples_orig[0] * nOutChannels ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing output file: %s\n", ivas_error_to_string( error ) ); + goto cleanup; + } +#ifdef SPLIT_REND_WITH_HEAD_ROT + } +#endif + + /*------------------------------------------------------------------------------------------* + * Printouts after decoding has finished + *------------------------------------------------------------------------------------------*/ + + if ( !arg.quietModeEnabled ) + { + printf( "\n\nDecoder+renderer delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[1] / (float) delayTimeScale, delayNumSamples_orig[1], delayTimeScale ); + + if ( delayNumSamples_orig[2] > 0 ) + { + printf( "HRIR/BRIR delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * delayNumSamples_orig[2] / (float) delayTimeScale, delayNumSamples_orig[2], delayTimeScale ); + printf( "Total delay: %4.2f ms (%3u samples at timescale %5u)\n", 1000.f * ( delayNumSamples_orig[1] + delayNumSamples_orig[2] ) / (float) delayTimeScale, delayNumSamples_orig[1] + delayNumSamples_orig[2], delayTimeScale ); + } + } /* Print output metadata file name(s) */ if ( arg.outputFormat == IVAS_DEC_OUTPUT_EXT ) @@ -2224,6 +2949,7 @@ cleanup: return error; } +#endif #ifdef DEBUGGING /*---------------------------------------------------------------------* @@ -2494,7 +3220,9 @@ static ivas_error decodeVoIP( while ( 1 ) { int16_t nOutSamples = 0; +#ifndef API_5MS uint16_t nSamplesAvailableNext = 0; +#endif #ifdef DEBUG_JBM_CMD_OPTION nOutSamples = (int16_t) ( arg.output_Fs / 1000 * arg.frontendFetchSizeMs ); #else @@ -2551,7 +3279,11 @@ static ivas_error decodeVoIP( /* decode and get samples */ - if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, pcmBuf, systemTime_ms, &nSamplesAvailableNext + if ( ( error = IVAS_DEC_VoIP_GetSamples( hIvasDec, nOutSamples, pcmBuf, systemTime_ms +#ifndef API_5MS + , + &nSamplesAvailableNext +#endif #ifdef SUPPORT_JBM_TRACEFILE , writeJbmTraceFileFrameWrapper, @@ -2767,6 +3499,7 @@ cleanup: #ifdef DEBUGGING +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING /*---------------------------------------------------------------------* * decodeVariableSpeed() @@ -2973,7 +3706,11 @@ static ivas_error decodeVariableSpeed( fprintf( stderr, "\nError: input bitstream file couldn't be read: %s \n\n", arg.inputBitstreamFilename ); goto cleanup; } +#ifdef API_5MS + IVAS_DEC_VoIP_SetScale( hIvasDec, scale, scale ); +#else IVAS_DEC_VoIP_SetScale( hIvasDec, scale ); +#endif } if ( ( error = BS_Reader_ReadFrame_short( hBsReader, bit_stream, &num_bits, &bfi ) ) != IVAS_ERR_OK ) @@ -3247,7 +3984,7 @@ static ivas_error decodeVariableSpeed( } /* decode and get samples */ - if ( ( error = IVAS_DEC_VoIP_Flush( hIvasDec, nOutSamples, pcmBuf, &nSamplesAvailableNext, &nSamplesFlushed ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_DEC_Flush( hIvasDec, nOutSamples, pcmBuf, &nSamplesAvailableNext, &nSamplesFlushed ) ) != IVAS_ERR_OK ) { fprintf( stderr, "\nError in IVAS_DEC_VoIP_Flush: %s\n", IVAS_DEC_GetErrorMessage( error ) ); goto cleanup; @@ -3386,7 +4123,7 @@ cleanup: return error; } #endif - +#endif /*---------------------------------------------------------------------* * parseForcedRendModeDec() diff --git a/apps/renderer.c b/apps/renderer.c index 17c84d9b811cfa0306068c54054ce9d33b3ae911..8b4dbe8201838454645d980d07aedd6db7aaaf17 100644 --- a/apps/renderer.c +++ b/apps/renderer.c @@ -175,6 +175,9 @@ typedef struct float lfeConfigElevation; bool lfeCustomRoutingEnabled; char inLfePanningMatrixFile[RENDERER_MAX_CLI_ARG_LENGTH]; +#ifdef LIB_REND_API_5MS + bool framing_5ms; +#endif #ifdef FIX_488_SYNC_DELAY float syncMdDelay; #endif @@ -206,6 +209,9 @@ typedef enum #endif CmdLnOptionId_referenceVectorFile, CmdLnOptionId_exteriorOrientationFile, +#ifdef LIB_REND_API_5MS + CmdLnOptionId_framing5ms, +#endif #ifdef FIX_488_SYNC_DELAY CmdLnOptionId_syncMdDelay, #endif @@ -348,6 +354,14 @@ static const CmdLnParser_Option cliOptions[] = { .matchShort = "exof", .description = "External orientation trajectory file for simulation of external orientations", }, +#ifdef LIB_REND_API_5MS + { + .id = CmdLnOptionId_framing5ms, + .match = "framing_5ms", + .matchShort = "fr5", + .description = "Process audio with 5 ms framing. Time resolution of metadata (e.g. ISM positions) remains unchanged w.r.t. 20 ms framing", + }, +#endif #ifdef FIX_488_SYNC_DELAY { .id = CmdLnOptionId_syncMdDelay, @@ -787,7 +801,9 @@ int main( int32_t delayTimeScale = 0; int16_t i, numChannels; ivas_error error = IVAS_ERR_OK; +#ifndef LIB_REND_API_5MS IVAS_VECTOR3 Pos[RENDERER_HEAD_POSITIONS_PER_FRAME]; +#endif #ifdef WMOPS reset_wmops(); @@ -1011,7 +1027,13 @@ int main( #ifdef SPLIT_REND_WITH_HEAD_ROT } #endif - const int16_t frameSize_smpls = (int16_t) ( 20 * args.sampleRate / 1000 ); + const int16_t frameSize_smpls = (int16_t) ( +#ifdef LIB_REND_API_5MS + ( args.framing_5ms ? 5 : 20 ) +#else + 20 +#endif + * args.sampleRate / 1000 ); IVAS_REND_InputId mcIds[RENDERER_MAX_MC_INPUTS] = { 0 }; IVAS_REND_InputId ismIds[RENDERER_MAX_ISM_INPUTS] = { 0 }; @@ -1438,10 +1460,17 @@ int main( fprintf( stdout, "\n\n-- Start the renderer (quiet mode) --\n\n" ); } +#ifdef LIB_REND_API_5MS + ObjectPositionBuffer mtdBuffer; +#endif + while ( 1 ) { int16_t num_in_channels; num_in_channels = inBuffer.config.numChannels; +#ifdef LIB_REND_API_5MS + const bool isCurrentFrameMultipleOf20ms = !args.framing_5ms || frame % 4 == 0; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT numSamplesRead = 0; @@ -1484,50 +1513,91 @@ int main( } /* Convert from int to float and from interleaved to packed */ - convertInputBuffer( inpInt16Buffer, numSamplesRead, inBuffer.config.numSamplesPerChannel, num_in_channels, inFloatBuffer + convertInputBuffer( inpInt16Buffer, numSamplesRead, frameSize_smpls, num_in_channels, inFloatBuffer #ifdef SPLIT_REND_WITH_HEAD_ROT , inBuffer.config.is_cldfb, cldfbAna #endif - ); + ); +#ifdef LIB_REND_API_5MS + if ( isCurrentFrameMultipleOf20ms ) + { +#else ObjectPositionBuffer mtdBuffer; - IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); +#endif + IsmPositionProvider_getNextFrame( positionProvider, &mtdBuffer ); - if ( referenceVectorReader != NULL ) - { - IVAS_VECTOR3 listenerPos, refPos; - if ( ( error = Vector3PairFileReader_read( referenceVectorReader, &listenerPos, &refPos ) ) != IVAS_ERR_OK ) + if ( referenceVectorReader != NULL ) { - fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) ); - exit( -1 ); + IVAS_VECTOR3 listenerPos, refPos; + if ( ( error = Vector3PairFileReader_read( referenceVectorReader, &listenerPos, &refPos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + if ( ( error = IVAS_REND_SetReferenceVector( hIvasRend, listenerPos, refPos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } } - if ( ( error = IVAS_REND_SetReferenceVector( hIvasRend, listenerPos, refPos ) ) != IVAS_ERR_OK ) + /* Read from reference rotation trajectory file if specified */ + if ( referenceRotReader != NULL ) { - fprintf( stderr, "Error: %s\n", ivas_error_to_string( error ) ); - exit( -1 ); + IVAS_QUATERNION quaternion; + if ( ( error = HeadRotationFileReading( referenceRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in Head Rotation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + + if ( ( error = IVAS_REND_SetReferenceRotation( hIvasRend, quaternion ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error setting Reference Rotation: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } } +#ifdef LIB_REND_API_5MS } - /* Read from reference rotation trajectory file if specified */ - if ( referenceRotReader != NULL ) +#endif + + /* Read from head rotation trajectory file if specified */ + if ( headRotReader != NULL ) { - IVAS_QUATERNION quaternion; - if ( ( error = HeadRotationFileReading( referenceRotReader, &quaternion, NULL ) ) != IVAS_ERR_OK ) +#ifdef LIB_REND_API_5MS + IVAS_QUATERNION headRot; + IVAS_VECTOR3 Pos; + + if ( ( error = HeadRotationFileReading( headRotReader, &headRot, &Pos ) ) != IVAS_ERR_OK ) { fprintf( stderr, "Error in Head Rotation File Reading: %s\n", ivas_error_to_string( error ) ); exit( -1 ); } - - if ( ( error = IVAS_REND_SetReferenceRotation( hIvasRend, quaternion ) ) != IVAS_ERR_OK ) + if ( ( error = IVAS_REND_SetHeadRotation( hIvasRend, headRot, Pos +#ifdef SPLIT_REND_WITH_HEAD_ROT + , + DEFAULT_AXIS +#endif + ) ) != IVAS_ERR_OK ) { - fprintf( stderr, "Error setting Reference Rotation: %s\n", ivas_error_to_string( error ) ); + fprintf( stderr, "Error setting Head Rotation: %s\n", ivas_error_to_string( error ) ); exit( -1 ); } - } - /* Read from head rotation trajectory file if specified */ - if ( headRotReader != NULL ) - { + if ( !args.framing_5ms ) + { + /* Skip over 3 following head positions - they are given on 5ms grid */ + for ( i = 0; i < 3; ++i ) + { + if ( ( error = HeadRotationFileReading( headRotReader, &headRot, &Pos ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in Head Rotation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + } + } +#else IVAS_QUATERNION quatBuffer[RENDERER_HEAD_POSITIONS_PER_FRAME]; for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) @@ -1548,20 +1618,29 @@ int main( fprintf( stderr, "Error setting Head Rotation: %s\n", ivas_error_to_string( error ) ); exit( -1 ); } +#endif } else { +#ifdef LIB_REND_API_5MS + if ( ( error = IVAS_REND_DisableHeadRotation( hIvasRend ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error disabling head rotation: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } +#else /* LIB_REND_API_5MS */ error = IVAS_REND_SetHeadRotation( hIvasRend, NULL, NULL #ifdef SPLIT_REND_WITH_HEAD_ROT , DEFAULT_AXIS #endif - ); + ); if ( error != IVAS_ERR_OK && error != IVAS_ERR_INVALID_OUTPUT_FORMAT ) { fprintf( stderr, "Error setting Head Rotation: %s\n", ivas_error_to_string( error ) ); exit( -1 ); } +#endif /* LIB_REND_API_5MS */ } #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -1576,6 +1655,38 @@ int main( /* Read from external orientation file if specified */ if ( externalOrientationFileReader != NULL ) { +#ifdef LIB_REND_API_5MS + IVAS_QUATERNION quat; + int8_t enableHeadRotation; + int8_t enableExternalOrientation; + int8_t enableRotationInterpolation; + int16_t numFramesToTargetOrientation; + + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &quat, &enableHeadRotation, &enableExternalOrientation, &enableRotationInterpolation, &numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in External Orientation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + + if ( ( error = IVAS_REND_SetExternalOrientation( hIvasRend, &quat, enableHeadRotation, enableExternalOrientation, enableRotationInterpolation, numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error setting External Orientation: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + + if ( !args.framing_5ms ) + { + /* Skip over 3 following entries in file - they are given on 5ms grid */ + for ( i = 0; i < 3; ++i ) + { + if ( ( error = ExternalOrientationFileReading( externalOrientationFileReader, &quat, &enableHeadRotation, &enableExternalOrientation, &enableRotationInterpolation, &numFramesToTargetOrientation ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "Error in External Orientation File Reading: %s\n", ivas_error_to_string( error ) ); + exit( -1 ); + } + } + } +#else IVAS_QUATERNION quatBuffer[RENDERER_HEAD_POSITIONS_PER_FRAME]; int8_t enableHeadRotation[RENDERER_HEAD_POSITIONS_PER_FRAME]; int8_t enableExternalOrientation[RENDERER_HEAD_POSITIONS_PER_FRAME]; @@ -1596,6 +1707,7 @@ int main( fprintf( stderr, "Error setting External Orientation: %s\n", ivas_error_to_string( error ) ); exit( -1 ); } +#endif } /* Combine external orientations and head rotation */ @@ -1815,6 +1927,7 @@ int main( #endif + /* TODO(sgi): Masa output most likely broken with 5ms framing */ /* Write MASA metadata for MASA outputs */ if ( args.outConfig.audioConfig == IVAS_REND_AUDIO_CONFIG_MASA1 || args.outConfig.audioConfig == IVAS_REND_AUDIO_CONFIG_MASA2 ) { @@ -2509,7 +2622,9 @@ static CmdlnArgs defaultArgs( args.lfeCustomRoutingEnabled = false; clearString( args.inLfePanningMatrixFile ); - +#ifdef LIB_REND_API_5MS + args.framing_5ms = false; +#endif #ifdef FIX_488_SYNC_DELAY args.syncMdDelay = 0; #endif @@ -2652,6 +2767,12 @@ static void parseOption( exit( -1 ); } break; +#ifdef LIB_REND_API_5MS + case CmdLnOptionId_framing5ms: + assert( numOptionValues == 0 ); + args->framing_5ms = true; + break; +#endif #ifdef FIX_488_SYNC_DELAY case CmdLnOptionId_syncMdDelay: assert( numOptionValues == 1 ); diff --git a/lib_com/common_api_types.h b/lib_com/common_api_types.h index 59f63879350f94c087720ff95b09b8e3c3f889e7..a4c7b97050fad74200e86fd236ca7788ff15adf1 100644 --- a/lib_com/common_api_types.h +++ b/lib_com/common_api_types.h @@ -50,7 +50,9 @@ #define IVAS_CLDFB_NO_CHANNELS_MAX ( 60 ) #define IVAS_MAX_INPUT_LFE_CHANNELS 4 +#ifndef LIB_REND_API_5MS #define RENDERER_HEAD_POSITIONS_PER_FRAME 4 +#endif /*----------------------------------------------------------------------------------* diff --git a/lib_com/ivas_error.h b/lib_com/ivas_error.h index e04b40468057c513aa017f8c8ca1a1bf719d9870..9732638af6465825b2f4bc62d7dc005ca821e421 100644 --- a/lib_com/ivas_error.h +++ b/lib_com/ivas_error.h @@ -86,6 +86,10 @@ typedef enum IVAS_ERR_ISM_INVALID_METADATA_VALUE, IVAS_ERR_INVALID_MASA_FORMAT_METADATA_FILE, IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, +#ifdef API_5MS + IVAS_ERR_TSM_NOT_ENABLED, + IVAS_ERR_FETCH_SIZE_NO_MULTIPLE_OF_5MS, +#endif #ifdef DEBUGGING IVAS_ERR_INVALID_FORCE_MODE, #ifdef DEBUG_AGC_ENCODER_CMD_OPTION diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 885de082817bae5459551d03c98c3aaf853071b5..6e422151a6ac3a9ee937ab4634a4b5a7c81db653 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -305,6 +305,7 @@ void stereo_dmx_evs_close_encoder( STEREO_DMX_EVS_ENC_HANDLE *hStereoDmxEVS /* i/o: Stereo downmix for EVS encoder handle */ ); +#ifndef API_5MS ivas_error ivas_dec( Decoder_Struct *st_ivas, /* i : IVAS decoder structure */ int16_t *data /* o : output synthesis signal */ @@ -313,6 +314,7 @@ ivas_error ivas_dec( IVAS_SPLIT_REND_BITS_HANDLE hSplitRendBits #endif ); +#endif ivas_error ivas_dec_setup( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ @@ -823,6 +825,13 @@ int16_t ivas_jbm_dec_get_num_tc_channels( Decoder_Struct *st_ivas /* i : IVAS decoder handle */ ); +#ifdef API_5MS +void ivas_jbm_dec_copy_tc_no_tsm( + Decoder_Struct *st_ivas, + float *tc[], + const int16_t output_frame ); +#endif + #ifdef FIX_470_MASA_JBM_EXT void ivas_jbm_dec_get_md_map_even_spacing( const int16_t default_len, /* i : default frame length in metadata slots */ @@ -1064,6 +1073,15 @@ void ivas_param_ism_dec_digest_tc( float *transport_channels_f[] /* i : synthesized core-coder transport channels/DirAC output */ ); +#ifdef API_5MS +void ivas_ism_param_dec_tc_gain_ajust( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const uint16_t nSamples, /* i : number of samples to be compensate */ + const uint16_t nFadeLength, /* i : length of the crossfade in samples */ + float *transport_channels_f[] /* i : synthesized core-coder transport channels/DirAC output */ +); +#endif + void ivas_param_ism_dec_render( Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ @@ -3611,6 +3629,9 @@ void ivas_dirac_dec( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ +#ifdef LIB_REND_API_5MS + ,const int16_t num_subframes /* i : number of subframes to render */ +#endif ); void ivas_dirac_dec_render( @@ -5078,7 +5099,9 @@ void ivas_binRenderer( HEAD_TRACK_DATA_HANDLE hPostRendHeadTrackData, #endif COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined head and external orientation handle */ +#ifndef API_5MS int16_t subframe_idx, /* i : subframe index */ +#endif const int16_t numTimeSlots, /* i: : number of time slots to process */ #ifdef SPLIT_REND_WITH_HEAD_ROT float Cldfb_RealBuffer_Binaural[][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Rotated Binaural signals */ @@ -5087,8 +5110,8 @@ void ivas_binRenderer( float Cldfb_RealBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ float Cldfb_ImagBuffer_Binaural[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* o : Binaural signals */ #endif - float RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i : LS signals */ - float ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX] /* i : LS signals */ + float RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i : LS signals */ + float ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX] /* i : LS signals */ ); void ivas_binaural_add_LFE( diff --git a/lib_com/options.h b/lib_com/options.h old mode 100755 new mode 100644 index c2bc0b866b05b09d53460339bca577ae01a9052d..cb7750d46f0f88fe54c816543b7985e8a93c0082 --- a/lib_com/options.h +++ b/lib_com/options.h @@ -128,6 +128,7 @@ /*#define DEBUG_AGC_ENCODER_CMD_OPTION*/ /* Ability to force enable or disable AGC behaviour in DIRAC/SPAR via command line option */ #define DEBUG_JBM_CMD_OPTION /* ability for telling the decoder the frontend fetch size and to not delay compensate for bad frames at the beginning */ #define VARIABLE_SPEED_DECODING /* variable speed decoding employing the JBM functioniality; move to DEBUGGING after build for disabled is fixed */ +/*#define DISABLE_LIMITER*/ #define DEBUG_IND_LIST_MEMORY /* raise assert() when ind_list[] runs out of memory */ /*Split Rendering Debug switches*/ @@ -155,6 +156,20 @@ #define FIX_137_SID_MD_BITS /* Dlb: Fix issue #137 , SID bitrate mismatch correction */ #define FIX_470_MASA_JBM_EXT /* Nokia: Issue 470, fix MASA EXT output with JBM */ #define FIX_564 /* Nokia: Issue 564: Fix gains in JBM path for SBA with parametric binaural renderer */ +// 5 ms branch switches start +// TODO: Check all switches in this section, remove if they were accepted +#define FIX_566_2DIR_MASA_384K /* Nokia: Issued 566: Bugfix in 384k MASA metadata encoding of second direction */ +#define FIX_XXX_HEADTRACKER_INIT +#define FIX_XXX_TDOBJRENDERER_INPUT /* sgi2bay: seems like this is already covered under FIX_550_FIRST_FRAME_ACCESS */ +#define FIX_XXX_ISM_SBA_ASAN +#define NONBE_FIX_589_JBM_TC_OFFSETS +#define API_5MS +#ifdef API_5MS +#define JITTER_MEM_OPTIM_RENDERING +#define LIB_REND_API_5MS /* FhG: Adds 5ms framing capability to lib_rend */ /* TODO(sgi): needs to be joined with API_5MS */ +#endif +#define LIB_REND_FIX_HRTFPARAMBIN_MEMLEAK +// 5 ms branch switches end #define FIX_559_EXTL_IGF_MISMATCH /* VA: issue 559: fix mismatch between st->extl and st->igf observed as crash in PlanarSBA bitrate switching */ #define FIX_571_REVERB_NOT_ACTIVATED_ISM /* Philips: Issue 571: Reverb not activated for discrete and parametric ISM */ #define FIX_QMETA_SID_5k2 /* Nokia: Issue 137: enable using full 5.2k bitrate in MASA SID */ diff --git a/lib_dec/ivas_binRenderer_internal.c b/lib_dec/ivas_binRenderer_internal.c index 1c7372c9329b39a71f5b7f9ebd411e8c89105438..c01769aaaa9f6b0db1eb2a2ccdf45bd5691185a4 100644 --- a/lib_dec/ivas_binRenderer_internal.c +++ b/lib_dec/ivas_binRenderer_internal.c @@ -1312,18 +1312,23 @@ void ivas_binaural_cldfb( } /* Implement binaural rendering */ - ivas_binRenderer( st_ivas->hBinRenderer, + ivas_binRenderer( + st_ivas->hBinRenderer, #ifdef SPLIT_REND_WITH_HEAD_ROT - &st_ivas->splitBinRend.splitrend.multiBinPoseData, + &st_ivas->splitBinRend.splitrend.multiBinPoseData, #endif - st_ivas->hCombinedOrientationData, - subframeIdx, JBM_CLDFB_SLOTS_IN_SUBFRAME, + st_ivas->hCombinedOrientationData, +#ifndef API_5MS + subframeIdx, +#endif + JBM_CLDFB_SLOTS_IN_SUBFRAME, #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG NULL, #endif - Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, - Cldfb_RealBuffer, - Cldfb_ImagBuffer ); + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, + Cldfb_RealBuffer, + Cldfb_ImagBuffer ); /* Implement CLDFB synthesis */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) @@ -1434,12 +1439,20 @@ void ivas_binaural_cldfb_sf( } /* Implement binaural rendering */ - ivas_binRenderer( st_ivas->hBinRenderer, + ivas_binRenderer( + st_ivas->hBinRenderer, #ifdef SPLIT_REND_WITH_HEAD_ROT - &st_ivas->splitBinRend.splitrend.multiBinPoseData, + &st_ivas->splitBinRend.splitrend.multiBinPoseData, #endif - st_ivas->hCombinedOrientationData, subframeIdx, st_ivas->hTcBuffer->subframe_nbslots[subframeIdx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); - + st_ivas->hCombinedOrientationData, +#ifndef API_5MS + subframeIdx, +#endif + st_ivas->hTcBuffer->subframe_nbslots[subframeIdx], + Cldfb_RealBuffer_Binaural, + Cldfb_ImagBuffer_Binaural, + Cldfb_RealBuffer, + Cldfb_ImagBuffer ); /* Implement CLDFB synthesis */ for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ ) { @@ -1476,13 +1489,15 @@ void ivas_binaural_cldfb_sf( *-------------------------------------------------------------------------*/ void ivas_binRenderer( - BINAURAL_RENDERER_HANDLE hBinRenderer, /* i/o: binaural renderer handle */ + BINAURAL_RENDERER_HANDLE hBinRenderer, /* i/o: binaural renderer handle */ #ifdef SPLIT_REND_WITH_HEAD_ROT const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, #endif - COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined head and external orientation handle */ - int16_t subframe_idx, /* i : subframe index */ - const int16_t numTimeSlots, + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined head and external orientation handle*/ +#ifndef API_5MS + int16_t subframe_idx, /* i : subframe index */ +#endif + const int16_t numTimeSlots, /* i : number of time slots to render */ #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG HEAD_TRACK_DATA_HANDLE hPostRendHeadTrackData, #endif @@ -1533,25 +1548,40 @@ void ivas_binRenderer( #endif /* SPLIT_REND_WITH_HEAD_ROT */ /* Head rotation in HOA3 or CICPx */ - if ( - hCombinedOrientationData != NULL && hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && hBinRenderer->rotInCldfb ) +#ifdef API_5MS + if ( hCombinedOrientationData != NULL && hCombinedOrientationData->enableCombinedOrientation && hBinRenderer->rotInCldfb ) +#else + if ( hCombinedOrientationData != NULL && hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && hBinRenderer->rotInCldfb ) +#endif { if ( hBinRenderer->hInputSetup->is_loudspeaker_setup == 0 ) { /* Rotation in SHD (HOA3) */ if ( hCombinedOrientationData->shd_rot_max_order == -1 ) { +#ifdef API_5MS + rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat, hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, 3 ); +#else rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat[subframe_idx], hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, 3 ); +#endif } else if ( hCombinedOrientationData->shd_rot_max_order > 0 ) { +#ifdef API_5MS + rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat, hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, hCombinedOrientationData->shd_rot_max_order ); +#else rotateFrame_shd_cldfb( RealBuffer, ImagBuffer, hCombinedOrientationData->Rmat[subframe_idx], hBinRenderer->hInputSetup->nchan_out_woLFE, numTimeSlots, hCombinedOrientationData->shd_rot_max_order ); +#endif } } else { /* Rotation in SD (CICPx) */ +#ifdef API_5MS + rotateFrame_sd_cldfb( hCombinedOrientationData->Rmat, RealBuffer, ImagBuffer, hBinRenderer->hInputSetup, hBinRenderer->hEFAPdata, numTimeSlots, hBinRenderer->conv_band ); +#else rotateFrame_sd_cldfb( hCombinedOrientationData->Rmat[subframe_idx], RealBuffer, ImagBuffer, hBinRenderer->hInputSetup, hBinRenderer->hEFAPdata, numTimeSlots, hBinRenderer->conv_band ); +#endif } } @@ -1578,7 +1608,11 @@ void ivas_binRenderer( if ( hCombinedOrientationData && hBinRenderer->rotInCldfb ) { +#ifdef API_5MS + Quaternions_ref = &hCombinedOrientationData->Quaternion; +#else Quaternions_ref = &hCombinedOrientationData->Quaternions[0]; +#endif Quaternions_rel.w = -3.0f; /*euler*/ Quaternions_abs.w = -3.0f; /*euler*/ Quat2EulerDegree( *Quaternions_ref, &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ @@ -1692,12 +1726,17 @@ void ivas_rend_CldfbMultiBinRendProcess( float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX]; #endif - +#ifndef API_5MS for ( sf_idx = 0; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ ) { - for ( slot_idx = 0; slot_idx < MAX_PARAM_SPATIAL_SUBFRAMES; slot_idx++ ) +#endif + for ( slot_idx = 0; slot_idx < MAX_PARAM_SPATIAL_SUBFRAMES; slot_idx++ ) /* FhG@Dolby: this looks suspicious */ { +#ifdef API_5MS + idx = slot_idx; +#else idx = sf_idx * MAX_PARAM_SPATIAL_SUBFRAMES + slot_idx; +#endif for ( ch_idx = 0; ch_idx < hCldfbRend->nInChannels; ch_idx++ ) { mvr2r( &Cldfb_In_Real[ch_idx][idx][0], &Cldfb_RealBuffer_sfIn[ch_idx][slot_idx][0], hCldfbRend->max_band ); @@ -1709,12 +1748,18 @@ void ivas_rend_CldfbMultiBinRendProcess( { if ( ( low_res_pre_rend_rot ) && ( pMultiBinPoseData->poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) ) { +#ifdef API_5MS + ( *pCombinedOrientationData )->Quaternion = ( *pCombinedOrientationData )->Quaternion; +#else ( *pCombinedOrientationData )->Quaternions[sf_idx] = ( *pCombinedOrientationData )->Quaternions[0]; +#endif for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { - ( *pCombinedOrientationData )->Rmat[sf_idx][i][j] = ( *pCombinedOrientationData )->Rmat[0][i][j]; +#ifdef API_5MS + ( *pCombinedOrientationData )->Rmat[i][j] = ( *pCombinedOrientationData )->Rmat[i][j]; +#endif } } } @@ -1728,7 +1773,11 @@ void ivas_rend_CldfbMultiBinRendProcess( ivas_binRenderer( hCldfbRend, pMultiBinPoseData, - *pCombinedOrientationData, sf_idx, MAX_PARAM_SPATIAL_SUBFRAMES, + *pCombinedOrientationData, +#ifndef API_5MS + sf_idx, +#endif + MAX_PARAM_SPATIAL_SUBFRAMES, #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG &head_track_post, #endif @@ -1746,7 +1795,9 @@ void ivas_rend_CldfbMultiBinRendProcess( } } } +#ifndef API_5MS } +#endif return; } diff --git a/lib_dec/ivas_dec.c b/lib_dec/ivas_dec.c index 5ca878a00ec58382864b493b2665782dbb4f20a9..465e2df11b6281c4e6bfafff40b334dd39e81df6 100644 --- a/lib_dec/ivas_dec.c +++ b/lib_dec/ivas_dec.c @@ -32,6 +32,7 @@ #include #include "options.h" +#ifndef API_5MS #include "cnst.h" #include "ivas_cnst.h" #include "rom_com.h" @@ -869,8 +870,9 @@ ivas_error ivas_dec( * - compensation for saturation * - float to integer conversion *----------------------------------------------------------------*/ - +#ifndef DISABLE_LIMITER ivas_limiter_dec( st_ivas->hLimiter, p_output, nchan_out, output_frame, st_ivas->BER_detect ); +#endif #ifdef DEBUGGING st_ivas->noClipping += @@ -909,3 +911,4 @@ ivas_error ivas_dec( pop_wmops(); return error; } +#endif diff --git a/lib_dec/ivas_dirac_dec.c b/lib_dec/ivas_dirac_dec.c index 766f4ff08fe05ea389e53845c393a6b5fda5f734..a8f81b21a3b64486ae1a228a28960093c2baf28a 100644 --- a/lib_dec/ivas_dirac_dec.c +++ b/lib_dec/ivas_dirac_dec.c @@ -925,7 +925,11 @@ ivas_error ivas_dirac_dec_config( /* Allocate transport channel buffers for SBA format when in JBM */ if ( dec_config_flag == DIRAC_OPEN ) { +#ifdef API_5MS + if ( st_ivas->hTcBuffer == NULL ) +#else if ( st_ivas->hDecoderConfig->voip_active == 1 && st_ivas->hTcBuffer == NULL ) +#endif { if ( st_ivas->ivas_format == SBA_FORMAT ) { @@ -1499,6 +1503,10 @@ void ivas_dirac_dec_set_md_map( hSpatParamRendCom->subframes_rendered = 0; ivas_jbm_dec_get_adapted_subframes( nCldfbTs, hSpatParamRendCom->subframe_nbslots, &hSpatParamRendCom->nb_subframes ); +#ifdef API_5MS + st_ivas->hTcBuffer->nb_subframes = hSpatParamRendCom->nb_subframes; + mvs2s( hSpatParamRendCom->subframe_nbslots, st_ivas->hTcBuffer->subframe_nbslots, hSpatParamRendCom->nb_subframes ); +#endif /* set mapping according to dirac_read_idx */ @@ -1555,6 +1563,10 @@ void ivas_dirac_dec( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ +#ifdef LIB_REND_API_5MS + , + const int16_t num_subframes /* i : number of subframes to render */ +#endif ) { int16_t subframe_idx; @@ -1587,7 +1599,11 @@ void ivas_dirac_dec( ivas_dirac_dec_set_md_map( st_ivas, DEFAULT_JBM_CLDFB_TIMESLOTS ); +#ifdef LIB_REND_API_5MS + for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ ) +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) +#endif { ivas_dirac_dec_render_sf( st_ivas, output_f_local, nchan_transport, NULL, NULL ); for ( n = 0; n < nchan_out; n++ ) @@ -1626,12 +1642,12 @@ void ivas_dirac_dec( *------------------------------------------------------------------------*/ void ivas_dirac_dec_render( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ - const int16_t nchan_transport, /* i : number of transport channels */ - const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ - uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ - uint16_t *nSamplesAvailable, /* o : number of CLDFB slots still to render */ - float *output_f[] /* o : rendered time signal */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const int16_t nchan_transport, /* i : number of transport channels */ + const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ + uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ + uint16_t *nSamplesAvailableNext, /* o : number of CLDFB slots still to render */ + float *output_f[] /* o : rendered time signal */ ) { int16_t slots_to_render, first_sf, last_sf, subframe_idx; @@ -1688,7 +1704,7 @@ void ivas_dirac_dec_render( } } - *nSamplesAvailable = ( hSpatParamRendCom->num_slots - hSpatParamRendCom->slots_rendered ) * slot_size; + *nSamplesAvailableNext = ( hSpatParamRendCom->num_slots - hSpatParamRendCom->slots_rendered ) * slot_size; return; } @@ -1826,9 +1842,17 @@ void ivas_dirac_dec_render_sf( set_zero( onset_filter_subframe, hSpatParamRendCom->num_freq_bands ); } +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation ) +#else if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] ) +#endif { +#ifdef API_5MS + p_Rmat = &st_ivas->hCombinedOrientationData->Rmat[0][0]; +#else p_Rmat = &st_ivas->hCombinedOrientationData->Rmat[subframe_idx][0][0]; +#endif if ( st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) { @@ -1892,7 +1916,11 @@ void ivas_dirac_dec_render_sf( set_zero( surCohRatio, hSpatParamRendCom->num_freq_bands ); } } +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation && st_ivas->hCombinedOrientationData->shd_rot_max_order == 1 ) +#else if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hCombinedOrientationData->shd_rot_max_order == 1 ) +#endif { ivas_dirac_dec_compute_directional_responses( hSpatParamRendCom, hDirACRend, @@ -1987,7 +2015,11 @@ void ivas_dirac_dec_render_sf( if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD ) { +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) +#else if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hCombinedOrientationData->shd_rot_max_order == 0 ) +#endif { protoSignalComputation_shd( Cldfb_RealBuffer, Cldfb_ImagBuffer, hDirACRend->h_output_synthesis_psd_state.proto_direct_buffer_f, @@ -2218,8 +2250,12 @@ void ivas_dirac_dec_render_sf( ivas_dirac_dec_compute_diffuse_proto( hDirACRend, hSpatParamRendCom->num_freq_bands, slot_idx ); } - /*Compute PSDs*/ +/*Compute PSDs*/ +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation && st_ivas->hCombinedOrientationData->shd_rot_max_order > 0 ) +#else if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] && st_ivas->hCombinedOrientationData->shd_rot_max_order > 0 ) +#endif { ivas_dirac_dec_output_synthesis_process_slot( reference_power, p_onset_filter, @@ -2321,7 +2357,9 @@ void ivas_dirac_dec_render_sf( &st_ivas->splitBinRend.splitrend.multiBinPoseData, #endif st_ivas->hCombinedOrientationData, +#ifndef API_5MS subframe_idx, +#endif hSpatParamRendCom->subframe_nbslots[subframe_idx], Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, diff --git a/lib_dec/ivas_init_dec.c b/lib_dec/ivas_init_dec.c index 616069f25fbe1000500cd49ff6179189ab351bcd..d042eed4ee74a2628bb0dd8582c45474a43d0511 100644 --- a/lib_dec/ivas_init_dec.c +++ b/lib_dec/ivas_init_dec.c @@ -618,6 +618,12 @@ ivas_error ivas_init_decoder_front( { return error; } +#ifdef FIX_XXX_HEADTRACKER_INIT + if ( ( error = ivas_orient_trk_SetTrackingType( st_ivas->hHeadTrackData->OrientationTracker, st_ivas->hDecoderConfig->orientation_tracking ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif } /*-------------------------------------------------------------------* @@ -790,6 +796,7 @@ ivas_error ivas_init_decoder( } } +#ifndef FIX_XXX_HEADTRACKER_INIT /*-----------------------------------------------------------------* * Set head/orientation tracking *-----------------------------------------------------------------*/ @@ -801,7 +808,7 @@ ivas_error ivas_init_decoder( return error; } } - +#endif /*-----------------------------------------------------------------* * Allocate and initialize SCE/CPE and other handles *-----------------------------------------------------------------*/ @@ -1371,7 +1378,10 @@ ivas_error ivas_init_decoder( } } #endif + +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active ) +#endif { granularity = NS2SA( st_ivas->hDecoderConfig->output_Fs, FRAME_SIZE_NS / MAX_PARAM_SPATIAL_SUBFRAMES ); n_channels_transport_jbm = ivas_jbm_dec_get_num_tc_channels( st_ivas ); @@ -1449,7 +1459,9 @@ ivas_error ivas_init_decoder( st_ivas->binaural_latency_ns = st_ivas->hCrendWrapper->binaural_latency_ns; +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active ) +#endif { #ifdef JBM_PARAMUPMIX if ( ( st_ivas->ivas_format == MC_FORMAT ) && ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) ) @@ -1579,8 +1591,11 @@ ivas_error ivas_init_decoder( /*-----------------------------------------------------------------* * Allocate and initialize JBM struct + buffer *-----------------------------------------------------------------*/ - +#ifdef API_5MS + if ( st_ivas->hTcBuffer == NULL ) +#else if ( st_ivas->hDecoderConfig->voip_active && st_ivas->hTcBuffer == NULL ) +#endif { /* no module has yet open the TC buffer, open a default one */ n_channels_transport_jbm = ivas_jbm_dec_get_num_tc_channels( st_ivas ); @@ -1591,6 +1606,7 @@ ivas_error ivas_init_decoder( } } +#ifndef API_5MS if ( st_ivas->hTcBuffer == NULL ) { /* we need the handle anyway, but without the buffer*/ @@ -1599,6 +1615,7 @@ ivas_error ivas_init_decoder( return error; } } +#endif #ifdef FIX_470_MASA_JBM_EXT if ( st_ivas->hJbmMetadata == NULL ) diff --git a/lib_dec/ivas_ism_dec.c b/lib_dec/ivas_ism_dec.c index 63464def7f1251008048659757c2a6f21b6228e3..b01dfd9e84c2be54424ec34c512e507c77d9d168 100644 --- a/lib_dec/ivas_ism_dec.c +++ b/lib_dec/ivas_ism_dec.c @@ -119,7 +119,9 @@ static ivas_error ivas_ism_bitrate_switching( ivas_output_init( &( st_ivas->hIntSetup ), st_ivas->hDecoderConfig->output_config ); } +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active ) +#endif { /* transfer subframe info from DirAC or ParamMC to central tc buffer */ if ( last_ism_mode == ISM_MODE_PARAM && st_ivas->hSpatParamRendCom != NULL && ( st_ivas->renderer_type != RENDERER_MONO_DOWNMIX && st_ivas->renderer_type != RENDERER_DISABLE ) ) @@ -319,8 +321,9 @@ static ivas_error ivas_ism_bitrate_switching( /*-----------------------------------------------------------------* * Reconfigure TC buffer *-----------------------------------------------------------------*/ - +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active == 1 ) +#endif { int16_t tc_nchan_full_new; DECODER_TC_BUFFER_HANDLE hTcBuffer; diff --git a/lib_dec/ivas_ism_param_dec.c b/lib_dec/ivas_ism_param_dec.c index 8cea5347b448516a5968080d4d7cccd9d79274e0..06208595a7f232e6db24a22d5b386593748cae15 100644 --- a/lib_dec/ivas_ism_param_dec.c +++ b/lib_dec/ivas_ism_param_dec.c @@ -524,7 +524,11 @@ ivas_error ivas_param_ism_dec_open( if ( !( output_config == AUDIO_CONFIG_MONO || output_config == AUDIO_CONFIG_STEREO ) ) { /* Initialize Param ISM Rendering handle */ +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) +#else if ( st_ivas->hDecoderConfig->voip_active ) +#endif { if ( ( error = ivas_param_ism_rendering_init( hDirAC->hParamIsmRendering, hOutSetup, st_ivas->nchan_transport, MAX_JBM_CLDFB_TIMESLOTS, output_config ) ) != IVAS_ERR_OK ) { @@ -577,7 +581,9 @@ ivas_error ivas_param_ism_dec_open( st_ivas->hDirAC = hDirAC; st_ivas->hSpatParamRendCom = hSpatParamRendCom; +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active ) +#endif { if ( st_ivas->renderer_type != RENDERER_MONO_DOWNMIX && st_ivas->renderer_type != RENDERER_DISABLE ) { @@ -591,7 +597,31 @@ ivas_error ivas_param_ism_dec_open( } else { +#ifdef API_5MS + int16_t n_slots_to_alloc; + if ( st_ivas->hDecoderConfig->tsm_active == 1 ) + { + n_slots_to_alloc = MAX_JBM_CLDFB_TIMESLOTS; + } + else + { + n_slots_to_alloc = CLDFB_SLOTS_PER_SUBFRAME * MAX_PARAM_SPATIAL_SUBFRAMES; + } + if ( ( hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc = (float *) malloc( n_slots_to_alloc * nchan_transport * hSpatParamRendCom->num_freq_bands * sizeof( float ) ) ) == NULL ) + + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Param ISM JBM Rendering handle\n" ) ); + } + set_zero( hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc, n_slots_to_alloc * nchan_transport * hSpatParamRendCom->num_freq_bands ); + + if ( ( hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc = (float *) malloc( n_slots_to_alloc * nchan_transport * hSpatParamRendCom->num_freq_bands * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Param ISM JBM Rendering handle\n" ) ); + } + set_zero( hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc, n_slots_to_alloc * nchan_transport * hSpatParamRendCom->num_freq_bands ); +#else if ( ( hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc = (float *) malloc( MAX_JBM_CLDFB_TIMESLOTS * nchan_transport * hSpatParamRendCom->num_freq_bands * sizeof( float ) ) ) == NULL ) + { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Param ISM JBM Rendering handle\n" ) ); } @@ -602,6 +632,7 @@ ivas_error ivas_param_ism_dec_open( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Param ISM JBM Rendering handle\n" ) ); } set_zero( hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc, MAX_JBM_CLDFB_TIMESLOTS * nchan_transport * hSpatParamRendCom->num_freq_bands ); +#endif } if ( st_ivas->hTcBuffer == NULL ) { @@ -625,11 +656,13 @@ ivas_error ivas_param_ism_dec_open( } } } +#ifndef API_5MS else { hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc = NULL; hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc = NULL; } +#endif pop_wmops(); return error; @@ -727,8 +760,12 @@ void ivas_param_ism_dec( int16_t subframe_idx, slot_idx, index_slot, bin_idx; int32_t ivas_total_brate; int16_t output_frame; +#ifndef API_5MS float gain, ene_tc, ene_sum, grad; float last_gain; +#else + float *p_tc[PARAM_ISM_MAX_DMX]; +#endif float ref_power[CLDFB_NO_CHANNELS_MAX]; float cx_diag[CLDFB_NO_CHANNELS_MAX][PARAM_ISM_MAX_DMX]; /* CLDFB Input Buffers */ @@ -755,9 +792,17 @@ void ivas_param_ism_dec( assert( hDirAC ); hSpatParamRendCom = st_ivas->hSpatParamRendCom; assert( hSpatParamRendCom ); +#ifdef API_5MS + for ( i = 0; i < PARAM_ISM_MAX_DMX; i++ ) + { + p_tc[i] = output_f[i]; + } +#else + ene_tc = 0.0f; ene_sum = 0.0f; last_gain = st_ivas->hDirAC->hParamIsm->last_dmx_gain; +#endif output_frame = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); nchan_transport = st_ivas->nchan_transport; @@ -841,7 +886,10 @@ void ivas_param_ism_dec( } } } - +#ifdef API_5MS + ivas_ism_param_dec_tc_gain_ajust( st_ivas, output_frame, output_frame / 2, p_tc ); +#else +#ifdef FIX_549_DMX_GAIN /* Energy Compensation */ for ( i = 0; i < output_frame; i++ ) { @@ -875,7 +923,8 @@ void ivas_param_ism_dec( } } st_ivas->hDirAC->hParamIsm->last_dmx_gain = gain; - +#endif /* FIX_549_DMX_GAIN */ +#endif /* API_5MS */ for ( ch = 0; ch < nchan_transport; ch++ ) { /*-----------------------------------------------------------------* @@ -1091,9 +1140,13 @@ void ivas_param_ism_dec_digest_tc( int16_t ch, nchan_transport, nchan_out, nchan_out_woLFE, i; int16_t slot_idx, bin_idx; int32_t ivas_total_brate; +#ifndef API_5MS +#ifdef FIX_549_DMX_GAIN int16_t output_frame; float gain, ene_tc, ene_sum, grad; float last_gain; +#endif +#endif float ref_power[CLDFB_NO_CHANNELS_MAX]; float cx_diag[CLDFB_NO_CHANNELS_MAX][PARAM_ISM_MAX_DMX]; /* Direct Response/EFAP Gains */ @@ -1106,10 +1159,14 @@ void ivas_param_ism_dec_digest_tc( assert( hDirAC ); hSpatParamRendCom = st_ivas->hSpatParamRendCom; assert( hSpatParamRendCom ); +#ifndef API_5MS +#ifdef FIX_549_DMX_GAIN ene_tc = 0.0f; ene_sum = 0.0f; last_gain = st_ivas->hDirAC->hParamIsm->last_dmx_gain; output_frame = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); +#endif +#endif nchan_transport = st_ivas->nchan_transport; ivas_total_brate = st_ivas->hDecoderConfig->ivas_total_brate; @@ -1195,7 +1252,13 @@ void ivas_param_ism_dec_digest_tc( } } } - +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) + { + ivas_ism_param_dec_tc_gain_ajust( st_ivas, nCldfbSlots * hSpatParamRendCom->num_freq_bands, (int16_t) ( st_ivas->hDecoderConfig->output_Fs / ( 2 * FRAMES_PER_SEC ) ), transport_channels_f ); + } +#else +#ifdef FIX_549_DMX_GAIN /* Energy Compensation */ for ( i = 0; i < output_frame; i++ ) { @@ -1229,6 +1292,8 @@ void ivas_param_ism_dec_digest_tc( } } st_ivas->hDirAC->hParamIsm->last_dmx_gain = gain; +#endif /* FIX_549_DMX_GAIN */ +#endif /* API_5MS */ for ( ch = 0; ch < nchan_transport; ch++ ) { @@ -1237,14 +1302,23 @@ void ivas_param_ism_dec_digest_tc( *-----------------------------------------------------------------*/ for ( slot_idx = 0; slot_idx < nCldfbSlots; slot_idx++ ) { - float RealBuffer[CLDFB_NO_CHANNELS_MAX]; - float ImagBuffer[CLDFB_NO_CHANNELS_MAX]; +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) + { +#endif - cldfbAnalysis_ts( &( transport_channels_f[ch][hSpatParamRendCom->num_freq_bands * slot_idx] ), RealBuffer, ImagBuffer, hSpatParamRendCom->num_freq_bands, st_ivas->cldfbAnaDec[ch] ); - mvr2r( RealBuffer, &hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], hSpatParamRendCom->num_freq_bands ); - mvr2r( ImagBuffer, &hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], hSpatParamRendCom->num_freq_bands ); + float RealBuffer[CLDFB_NO_CHANNELS_MAX]; + float ImagBuffer[CLDFB_NO_CHANNELS_MAX]; + cldfbAnalysis_ts( &( transport_channels_f[ch][hSpatParamRendCom->num_freq_bands * slot_idx] ), RealBuffer, ImagBuffer, hSpatParamRendCom->num_freq_bands, st_ivas->cldfbAnaDec[ch] ); + mvr2r( RealBuffer, &hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], hSpatParamRendCom->num_freq_bands ); + mvr2r( ImagBuffer, &hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], hSpatParamRendCom->num_freq_bands ); +#ifdef API_5MS + } + ivas_param_ism_collect_slot( hDirAC, &hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], &hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc[slot_idx * hSpatParamRendCom->num_freq_bands * nchan_transport + ch * hSpatParamRendCom->num_freq_bands], ch, ref_power, cx_diag ); +#else ivas_param_ism_collect_slot( hDirAC, RealBuffer, ImagBuffer, ch, ref_power, cx_diag ); +#endif } } @@ -1263,6 +1337,67 @@ void ivas_param_ism_dec_digest_tc( } +#ifdef API_5MS +/*-------------------------------------------------------------------------* + * ivas_ism_param_dec_tc_gain_ajust() + * + * + *-------------------------------------------------------------------------*/ + +void ivas_ism_param_dec_tc_gain_ajust( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const uint16_t nSamples, /* i : number of samples to be compensate */ + const uint16_t nFadeLength, /* i : length of the crossfade in samples */ + float *transport_channels_f[] /* i : synthesized core-coder transport channels/DirAC output */ +) + +{ + int16_t i; + float gain, ene_tc, ene_sum, grad; + float last_gain; + + ene_tc = 0.0f; + ene_sum = 0.0f; + last_gain = st_ivas->hDirAC->hParamIsm->last_dmx_gain; + + + for ( i = 0; i < nSamples; i++ ) + { + ene_tc += transport_channels_f[0][i] * transport_channels_f[0][i] + transport_channels_f[1][i] * transport_channels_f[1][i]; // L*L + R*R + ene_sum += ( transport_channels_f[0][i] + transport_channels_f[1][i] ) * ( transport_channels_f[0][i] + transport_channels_f[1][i] ); // (L+R)*(L+R) + } + gain = sqrtf( ene_tc / ( ene_sum + EPSILON ) ); + if ( st_ivas->hSCE[0]->hCoreCoder[0]->ini_frame > 1 ) + { + /* Smoothing */ + gain = 0.75f * gain + 0.25f * last_gain; + /* 10ms ramp */ + grad = ( gain - last_gain ) / (float) nFadeLength; /* slope between two consecutive gains, 480 samples length */ + for ( i = 0; i < ( nFadeLength ); i++ ) + { + transport_channels_f[0][i] *= ( last_gain + i * grad ); + transport_channels_f[1][i] *= ( last_gain + i * grad ); + } + for ( ; i < nSamples; i++ ) + { + transport_channels_f[0][i] *= gain; + transport_channels_f[1][i] *= gain; + } + } + else + { + for ( i = 0; i < nSamples; i++ ) + { + transport_channels_f[0][i] *= gain; + transport_channels_f[1][i] *= gain; + } + } + st_ivas->hDirAC->hParamIsm->last_dmx_gain = gain; + + return; +} +#endif + /*-------------------------------------------------------------------------* * ivas_ism_param_dec_render_sf() * @@ -1368,11 +1503,11 @@ static void ivas_ism_param_dec_render_sf( *-------------------------------------------------------------------------*/ void ivas_param_ism_dec_render( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ - const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ - uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ - uint16_t *nSamplesAvailable, /* o : number of CLDFB slots still to render */ - float *output_f[] /* o : rendered time signal */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ + uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ + uint16_t *nSamplesAvailableNext, /* o : number of CLDFB slots still to render */ + float *output_f[] /* o : rendered time signal */ ) { int16_t ch, slots_to_render, first_sf, last_sf, subframe_idx; @@ -1456,7 +1591,7 @@ void ivas_param_ism_dec_render( } } - *nSamplesAvailable = ( hSpatParamRendCom->num_slots - hSpatParamRendCom->slots_rendered ) * slot_size; + *nSamplesAvailableNext = ( hSpatParamRendCom->num_slots - hSpatParamRendCom->slots_rendered ) * slot_size; return; } diff --git a/lib_dec/ivas_ism_renderer.c b/lib_dec/ivas_ism_renderer.c index 77563629aea067143dfffa3946f8dd46547b3afe..037f4a8b503c683064912d5456bc6ebaf7cb7808 100644 --- a/lib_dec/ivas_ism_renderer.c +++ b/lib_dec/ivas_ism_renderer.c @@ -82,7 +82,11 @@ ivas_error ivas_ism_renderer_open( set_f( st_ivas->hIsmRendererData->gains[i], 0.0f, MAX_OUTPUT_CHANNELS ); } +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) +#else if ( st_ivas->hDecoderConfig->voip_active ) +#endif { init_interpolator_length = NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_CLDFB_TIMESLOTS * CLDFB_SLOT_NS ); interpolator_length = (uint16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); @@ -155,9 +159,17 @@ void ivas_ism_render( else { /* Combined rotation: rotate the object positions depending the head and external orientations */ +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation == 1 ) +#else if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[0] == 1 ) +#endif { +#ifdef API_5MS + rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat, st_ivas->hIntSetup.is_planar_setup ); +#else rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat[0], st_ivas->hIntSetup.is_planar_setup ); +#endif } else { @@ -238,7 +250,11 @@ void ivas_ism_render_sf( set_f( output_f[i], 0.0f, n_samples_to_render ); } +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation ) +#else if ( st_ivas->hCombinedOrientationData && st_ivas->hCombinedOrientationData->enableCombinedOrientation[0] ) +#endif { ivas_jbm_dec_get_adapted_linear_interpolator( n_samples_to_render, n_samples_to_render, @@ -250,9 +266,17 @@ void ivas_ism_render_sf( { /* Combined rotation: rotate the object positions depending the head and external orientations */ +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation == 1 ) +#else if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[0] == 1 ) +#endif { +#ifdef API_5MS + rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat, st_ivas->hIntSetup.is_planar_setup ); +#else rotateAziEle( st_ivas->hIsmMetaData[i]->azimuth, st_ivas->hIsmMetaData[i]->elevation, &azimuth, &elevation, st_ivas->hCombinedOrientationData->Rmat[0], st_ivas->hIntSetup.is_planar_setup ); +#endif if ( st_ivas->hEFAPdata != NULL ) { efap_determine_gains( st_ivas->hEFAPdata, st_ivas->hIsmRendererData->gains[i], azimuth, elevation, EFAP_MODE_EFAP ); @@ -281,7 +305,11 @@ void ivas_ism_render_sf( } /* update here only in case of head rotation */ +#ifdef API_5MS + if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation == 1 ) +#else if ( st_ivas->hCombinedOrientationData != NULL && st_ivas->hCombinedOrientationData->enableCombinedOrientation[0] == 1 ) +#endif { st_ivas->hIsmRendererData->prev_gains[i][j] = gain; } diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index e1a7a9cbd28640a5357caa7cc844d572d8042af5..e1ebe3fa1fa7f3e4c8c3f6020e2fe66e248a5360 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -60,13 +60,11 @@ static void ivas_jbm_dec_copy_masa_meta_to_buffer( Decoder_Struct *st_ivas ); static void ivas_jbm_masa_sf_to_slot_map( Decoder_Struct *st_ivas, const int16_t nCldfbTs ); #endif - /*--------------------------------------------------------------------------* * ivas_jbm_dec_tc() * * Principal IVAS JBM decoder routine, decoding of metadata and transport channels *--------------------------------------------------------------------------*/ - ivas_error ivas_jbm_dec_tc( Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ float *data /* o : transport channel signals */ @@ -115,7 +113,7 @@ ivas_error ivas_jbm_dec_tc( /* zero output when first frame(s) is lost */ for ( n = 0; n < nchan_out; n++ ) { - set_f( output[n], 0.0f, output_frame ); + set_f( p_output[n], 0.0f, output_frame ); } #ifdef DEBUG_MODE_INFO @@ -128,7 +126,6 @@ ivas_error ivas_jbm_dec_tc( else if ( st_ivas->ivas_format == STEREO_FORMAT ) { st_ivas->hCPE[0]->element_brate = ivas_total_brate; - if ( ( error = ivas_cpe_dec( st_ivas, 0, output, output_frame, 0 ) ) != IVAS_ERR_OK ) { return error; @@ -525,15 +522,40 @@ ivas_error ivas_jbm_dec_tc( ivas_mono_stereo_downmix_mcmasa( st_ivas, output, output_frame ); } } +#ifdef API_5MS + else if ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) + { + + /* at least decode everything here, the rest is ToDo, for this we just output zeroes atm */ + ivas_lfe_dec( st_ivas->hLFE, st, output_frame, st_ivas->bfi, output_lfe_ch ); + + ivas_mc_paramupmix_dec_read_BS( st_ivas, st, st_ivas->hMCParamUpmix, &nb_bits_metadata[0] ); + + if ( ( error = ivas_mct_dec( st_ivas, output, output_frame, nb_bits_metadata[0] ) ) != IVAS_ERR_OK ) + { + return error; + } + } +#endif } /*----------------------------------------------------------------* * Write IVAS transport channels *----------------------------------------------------------------*/ - - ivas_syn_output_f( p_output, output_frame, st_ivas->hTcBuffer->nchan_transport_jbm, data ); - +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active == 1 ) + { +#endif + ivas_syn_output_f( p_output, output_frame, st_ivas->hTcBuffer->nchan_transport_jbm, data ); +#ifdef API_5MS + } + else + { + /* directly copy to tc buffers */ + ivas_jbm_dec_copy_tc_no_tsm( st_ivas, p_output, output_frame ); + } +#endif /*----------------------------------------------------------------* * Common updates @@ -597,7 +619,18 @@ ivas_error ivas_jbm_dec_feed_tc_to_renderer( { p_data_f[n] = &data_f[n][0]; } - ivas_jbm_dec_copy_tc( st_ivas, nSamplesForRendering, nSamplesResidual, data, p_data_f ); +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) + { +#endif + ivas_jbm_dec_copy_tc( st_ivas, nSamplesForRendering, nSamplesResidual, data, p_data_f ); +#ifdef API_5MS + } + else + { + *nSamplesResidual = 0; + } +#endif n_render_timeslots = st_ivas->hTcBuffer->n_samples_available / st_ivas->hTcBuffer->n_samples_granularity; if ( st_ivas->hTcBuffer->tc_buffer_mode == TC_BUFFER_MODE_BUFFER ) @@ -682,7 +715,12 @@ ivas_error ivas_jbm_dec_render( { int16_t n, nchan_out; int16_t nchan_transport; +#ifdef JITTER_MEM_OPTIM_RENDERING + uint16_t nSamplesRenderedLocal; + float output[MAX_OUTPUT_CHANNELS][L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES]; /* 'float' buffer for output synthesis, MAX_OUTPUT_CHANNELS channels */ +#else float output[MAX_OUTPUT_CHANNELS][L_FRAME48k]; /* 'float' buffer for output synthesis, MAX_OUTPUT_CHANNELS channels */ +#endif int16_t nchan_remapped; int32_t output_Fs; AUDIO_CONFIG output_config; @@ -706,63 +744,96 @@ ivas_error ivas_jbm_dec_render( nchan_out = st_ivas->hDecoderConfig->nchan_out; nchan_transport = st_ivas->hTcBuffer->nchan_transport_jbm; output_config = st_ivas->hDecoderConfig->output_config; +#ifndef JITTER_MEM_OPTIM_RENDERING nSamplesAskedLocal = nSamplesAsked + st_ivas->hTcBuffer->n_samples_discard; +#endif - for ( n = 0; n < MAX_OUTPUT_CHANNELS; n++ ) +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = 0; + *nSamplesRendered = 0; + while ( *nSamplesRendered < nSamplesAsked && st_ivas->hTcBuffer->n_samples_available > 0 ) { - p_output[n] = &output[n][0]; - } + uint16_t subframes_rendered = st_ivas->hTcBuffer->subframes_rendered; + nSamplesAskedLocal = st_ivas->hTcBuffer->subframe_nbslots[st_ivas->hTcBuffer->subframes_rendered] * st_ivas->hTcBuffer->n_samples_granularity; +#endif - for ( n = 0; n < st_ivas->hTcBuffer->nchan_transport_internal; n++ ) - { - p_tc[n] = &st_ivas->hTcBuffer->tc[n][st_ivas->hTcBuffer->n_samples_rendered]; - } + for ( n = 0; n < MAX_OUTPUT_CHANNELS; n++ ) + { + p_output[n] = &output[n][0]; + } - /*----------------------------------------------------------------* - * Combine orientations - *----------------------------------------------------------------*/ + for ( n = 0; n < st_ivas->hTcBuffer->nchan_transport_internal; n++ ) + { + p_tc[n] = &st_ivas->hTcBuffer->tc[n][st_ivas->hTcBuffer->n_samples_rendered]; + } - if ( ( error = combine_external_and_head_orientations_dec( st_ivas->hHeadTrackData, st_ivas->hExtOrientationData, - st_ivas->hCombinedOrientationData ) ) != IVAS_ERR_OK ) - { - return error; - } + /*----------------------------------------------------------------* + * Combine orientations + *----------------------------------------------------------------*/ - /*----------------------------------------------------------------* - * Rendering - *----------------------------------------------------------------*/ + if ( ( error = combine_external_and_head_orientations_dec( st_ivas->hHeadTrackData, st_ivas->hExtOrientationData, + st_ivas->hCombinedOrientationData ) ) != IVAS_ERR_OK ) + { + return error; + } - if ( st_ivas->ivas_format == UNDEFINED_FORMAT ) - { - assert( 0 ); - } - else if ( st_ivas->hTcBuffer->tc_buffer_mode == TC_BUFFER_MODE_BUFFER ) - { - ivas_jbm_dec_tc_buffer_playout( st_ivas, nSamplesAskedLocal, nSamplesRendered, p_output ); - } - else if ( st_ivas->ivas_format == STEREO_FORMAT ) - { - /* Rendering */ - if ( st_ivas->renderer_type == RENDERER_MC ) + /*----------------------------------------------------------------* + * Rendering + *----------------------------------------------------------------*/ + + if ( st_ivas->ivas_format == UNDEFINED_FORMAT ) { - *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); - ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); + assert( 0 ); } - } - else if ( st_ivas->ivas_format == ISM_FORMAT ) - { - /* Rendering */ - if ( st_ivas->ism_mode == ISM_MODE_PARAM ) + else if ( st_ivas->hTcBuffer->tc_buffer_mode == TC_BUFFER_MODE_BUFFER ) { - if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_jbm_dec_tc_buffer_playout( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, p_output ); +#else + ivas_jbm_dec_tc_buffer_playout( st_ivas, nSamplesAskedLocal, nSamplesRendered, p_output ); +#endif + } + else if ( st_ivas->ivas_format == STEREO_FORMAT ) + { + /* Rendering */ + if ( st_ivas->renderer_type == RENDERER_MC ) { - ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, st_ivas->nchan_transport, p_output ); +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); + ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, nSamplesRenderedLocal, p_tc, p_output ); + st_ivas->hTcBuffer->subframes_rendered++; +#else + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); + ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); +#endif } - else if ( st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) + } + else if ( st_ivas->ivas_format == ISM_FORMAT ) + { + /* Rendering */ + if ( st_ivas->ism_mode == ISM_MODE_PARAM ) { + if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, st_ivas->nchan_transport, p_output ); +#else + ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, st_ivas->nchan_transport, p_output ); +#endif + } + else if ( st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#else *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); - pan_left = ( st_ivas->hDecoderConfig->non_diegetic_pan_gain + 1.f ) * 0.5f; - pan_right = 1.f - pan_left; +#endif + pan_left = ( st_ivas->hDecoderConfig->non_diegetic_pan_gain + 1.f ) * 0.5f; + pan_right = 1.f - pan_left; +#ifdef JITTER_MEM_OPTIM_RENDERING + v_multc( p_tc[0], pan_right, output[1], nSamplesRenderedLocal ); + v_multc( p_tc[0], pan_left, output[0], nSamplesRenderedLocal ); +#else #ifdef NONBE_FIX_589_JBM_TC_OFFSETS v_multc( p_tc[0], pan_right, output[1], *nSamplesRendered ); v_multc( p_tc[0], pan_left, output[0], *nSamplesRendered ); @@ -770,280 +841,468 @@ ivas_error ivas_jbm_dec_render( v_multc( st_ivas->hTcBuffer->tc[0], pan_right, output[1], *nSamplesRendered ); v_multc( st_ivas->hTcBuffer->tc[0], pan_left, output[0], *nSamplesRendered ); #endif - } - else if ( st_ivas->renderer_type == RENDERER_PARAM_ISM || st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) - { - ivas_param_ism_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); - - if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) +#endif + } + else if ( st_ivas->renderer_type == RENDERER_PARAM_ISM || st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { - /* Convert CICP19 -> Ambisonics */ - ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_param_ism_dec_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, p_output ); +#else + ivas_param_ism_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); +#endif + if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) + { + /* Convert CICP19 -> Ambisonics */ +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, nSamplesRenderedLocal, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#else + ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#endif + } } - } - } - else /* ISM_MODE_DISC */ - { - *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); - /* Loudspeaker or Ambisonics rendering */ - if ( st_ivas->renderer_type == RENDERER_TD_PANNING || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) - { - /* Convert to CICPxx; used also for ISM->CICP19->binaural_room rendering */ - ivas_ism_render_sf( st_ivas, p_output, *nSamplesRendered ); +#ifdef JITTER_MEM_OPTIM_RENDERING + st_ivas->hTcBuffer->subframes_rendered++; +#endif } - else if ( st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) + else /* ISM_MODE_DISC */ { - pan_left = ( st_ivas->hDecoderConfig->non_diegetic_pan_gain + 1.f ) * 0.5f; - pan_right = 1.f - pan_left; +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#else + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#endif + /* Loudspeaker or Ambisonics rendering */ + if ( st_ivas->renderer_type == RENDERER_TD_PANNING || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) + { + /* Convert to CICPxx; used also for ISM->CICP19->binaural_room rendering */ +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_ism_render_sf( st_ivas, p_output, nSamplesRenderedLocal ); +#else + ivas_ism_render_sf( st_ivas, p_output, *nSamplesRendered ); +#endif + } + else if ( st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) + { + pan_left = ( st_ivas->hDecoderConfig->non_diegetic_pan_gain + 1.f ) * 0.5f; + pan_right = 1.f - pan_left; +#ifdef JITTER_MEM_OPTIM_RENDERING + v_multc( p_tc[0], pan_right, output[1], nSamplesRenderedLocal ); + v_multc( p_tc[0], pan_left, output[0], nSamplesRenderedLocal ); +#else #ifdef NONBE_FIX_589_JBM_TC_OFFSETS v_multc( p_tc[0], pan_right, output[1], *nSamplesRendered ); v_multc( p_tc[0], pan_left, output[0], *nSamplesRendered ); #else + v_multc( st_ivas->hTcBuffer->tc[0], pan_right, output[1], *nSamplesRendered ); v_multc( st_ivas->hTcBuffer->tc[0], pan_left, output[0], *nSamplesRendered ); #endif - } - else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV ) - { - /* Convert to Ambisonics; used also for ISM->HOA3->binaural rendering */ +#endif + } + else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV ) + { + /* Convert to Ambisonics; used also for ISM->HOA3->binaural rendering */ +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_ism2sba_sf( st_ivas->hTcBuffer->tc, p_output, st_ivas->hIsmRendererData, st_ivas->nchan_transport, nSamplesRenderedLocal, st_ivas->hTcBuffer->n_samples_rendered, st_ivas->hIntSetup.ambisonics_order ); +#else ivas_ism2sba_sf( st_ivas->hTcBuffer->tc, p_output, st_ivas->hIsmRendererData, st_ivas->nchan_transport, *nSamplesRendered, st_ivas->hTcBuffer->n_samples_rendered, st_ivas->hIntSetup.ambisonics_order ); - } +#endif + } - /* Binaural rendering */ - if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) - { - if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) + /* Binaural rendering */ + if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) { - return error; +#ifdef JITTER_MEM_OPTIM_RENDERING + if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, nSamplesRenderedLocal ) ) != IVAS_ERR_OK ) +#else + if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) +#endif + { + return error; + } } - } - else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) - { - if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, AUDIO_CONFIG_7_1_4, AUDIO_CONFIG_BINAURAL_ROOM_IR, st_ivas->hDecoderConfig, NULL, NULL, - NULL, st_ivas->hTcBuffer, p_output, p_output, *nSamplesRendered, output_Fs ) ) != IVAS_ERR_OK ) + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - return error; - } +#ifdef JITTER_MEM_OPTIM_RENDERING + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, AUDIO_CONFIG_7_1_4, AUDIO_CONFIG_BINAURAL_ROOM_IR, st_ivas->hDecoderConfig, NULL, NULL, + NULL, st_ivas->hTcBuffer, p_output, p_output, nSamplesRenderedLocal, output_Fs ) ) != IVAS_ERR_OK ) +#else + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, AUDIO_CONFIG_7_1_4, AUDIO_CONFIG_BINAURAL_ROOM_IR, st_ivas->hDecoderConfig, NULL, NULL, + NULL, st_ivas->hTcBuffer, p_output, p_output, *nSamplesRendered, output_Fs ) ) != IVAS_ERR_OK ) +#endif + { + return error; + } - ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); - } +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_binaural_add_LFE( st_ivas, nSamplesRenderedLocal, p_output, p_output ); +#else + ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); +#endif + } #ifdef DEBUGGING - else if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { -#ifdef JBM_PARAMUPMIX - ivas_binaural_cldfb_sf( st_ivas, *nSamplesRendered, st_ivas->hTcBuffer->nb_subframes, p_output ); + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) + { + ivas_binaural_cldfb_sf( + st_ivas, +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal, #else - ivas_binaural_cldfb_sf( st_ivas, *nSamplesRendered, p_output ); + *nSamplesRendered, #endif - } +#ifdef JBM_PARAMUPMIX + st_ivas->hTcBuffer->nb_subframes, #endif + p_output ); + } +#endif + } } - } - else if ( st_ivas->ivas_format == SBA_FORMAT || st_ivas->ivas_format == MASA_FORMAT ) - { - nchan_remapped = nchan_transport; - - /* Loudspeakers, Ambisonics or Binaural rendering */ - if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) + else if ( st_ivas->ivas_format == SBA_FORMAT || st_ivas->ivas_format == MASA_FORMAT ) { + nchan_remapped = nchan_transport; + + /* Loudspeakers, Ambisonics or Binaural rendering */ + if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, nchan_remapped, p_output ); +#else ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, nchan_remapped, p_output ); - } - else if ( st_ivas->ivas_format == MASA_FORMAT ) - { - if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_DEC ) +#endif + } + else if ( st_ivas->ivas_format == MASA_FORMAT ) { - *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); - for ( n = 0; n < nchan_remapped; n++ ) + if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_DEC ) { +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#else + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#endif + for ( n = 0; n < nchan_remapped; n++ ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + mvr2r( st_ivas->hTcBuffer->tc[n] + st_ivas->hTcBuffer->n_samples_rendered, p_output[n], nSamplesRenderedLocal ); +#else mvr2r( st_ivas->hTcBuffer->tc[n] + st_ivas->hTcBuffer->n_samples_rendered, p_output[n], *nSamplesRendered ); - } +#endif + } +#ifdef JITTER_MEM_OPTIM_RENDERING + if ( ( error = ivas_sba_linear_renderer( p_output, nSamplesRenderedLocal, nchan_remapped, output_config, st_ivas->hOutSetup, st_ivas->hoa_dec_mtx ) ) != IVAS_ERR_OK ) +#else if ( ( error = ivas_sba_linear_renderer( p_output, *nSamplesRendered, nchan_remapped, output_config, st_ivas->hOutSetup, st_ivas->hoa_dec_mtx ) ) != IVAS_ERR_OK ) +#endif + { + return error; + } + } + else if ( st_ivas->renderer_type == RENDERER_DIRAC ) { - return error; +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, p_output ); +#else + ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); +#endif } } - else if ( st_ivas->renderer_type == RENDERER_DIRAC ) + else /* SBA_MODE_SPAR */ { - ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); - } - } - else /* SBA_MODE_SPAR */ - { +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_sba_dec_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, p_output ); +#else ivas_sba_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); +#endif + } +#ifdef JITTER_MEM_OPTIM_RENDERING + st_ivas->hTcBuffer->subframes_rendered++; +#endif } - } - else if ( st_ivas->ivas_format == MC_FORMAT ) - { - if ( st_ivas->mc_mode == MC_MODE_MCT ) + else if ( st_ivas->ivas_format == MC_FORMAT ) { - *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); - if ( st_ivas->transport_config != st_ivas->intern_config && ( st_ivas->intern_config == AUDIO_CONFIG_FOA || st_ivas->intern_config == AUDIO_CONFIG_HOA2 || st_ivas->intern_config == AUDIO_CONFIG_HOA3 ) ) + if ( st_ivas->mc_mode == MC_MODE_MCT ) { +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#else + *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +#endif + if ( st_ivas->transport_config != st_ivas->intern_config && ( st_ivas->intern_config == AUDIO_CONFIG_FOA || st_ivas->intern_config == AUDIO_CONFIG_HOA2 || st_ivas->intern_config == AUDIO_CONFIG_HOA3 ) ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_mc2sba( st_ivas->hTransSetup, p_tc, p_output, nSamplesRenderedLocal, st_ivas->hIntSetup.ambisonics_order, GAIN_LFE ); +#else ivas_mc2sba( st_ivas->hTransSetup, p_tc, p_output, *nSamplesRendered, st_ivas->hIntSetup.ambisonics_order, GAIN_LFE ); - } +#endif + } - /* Rendering */ - if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) - { - if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, st_ivas->hCombinedOrientationData, - &st_ivas->hIntSetup, st_ivas->hEFAPdata, st_ivas->hTcBuffer, p_tc, p_output, *nSamplesRendered, output_Fs ) ) != IVAS_ERR_OK ) + /* Rendering */ + if ( st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV || st_ivas->renderer_type == RENDERER_BINAURAL_MIXER_CONV_ROOM ) { - return error; - } +#ifdef JITTER_MEM_OPTIM_RENDERING + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, + st_ivas->hCombinedOrientationData, + &st_ivas->hIntSetup, st_ivas->hEFAPdata, st_ivas->hTcBuffer, p_tc, p_output, nSamplesRenderedLocal, output_Fs ) ) != IVAS_ERR_OK ) +#else + if ( ( error = ivas_rend_crendProcessSubframe( st_ivas->hCrendWrapper, st_ivas->intern_config, st_ivas->hOutSetup.output_config, st_ivas->hDecoderConfig, + st_ivas->hCombinedOrientationData, + &st_ivas->hIntSetup, st_ivas->hEFAPdata, st_ivas->hTcBuffer, p_tc, p_output, *nSamplesRendered, output_Fs ) ) != IVAS_ERR_OK ) +#endif + { + return error; + } +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_binaural_add_LFE( st_ivas, nSamplesRenderedLocal, p_tc, p_output ); +#else #ifdef NONBE_FIX_589_JBM_TC_OFFSETS ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_tc, p_output ); #else ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, st_ivas->hTcBuffer->tc, p_output ); #endif - } - else if ( st_ivas->renderer_type == RENDERER_MC ) - { +#endif + } + else if ( st_ivas->renderer_type == RENDERER_MC ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); + ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, nSamplesRenderedLocal, p_tc, p_output ); +#else *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); ivas_ls_setup_conversion( st_ivas, st_ivas->nchan_transport, *nSamplesRendered, p_tc, p_output ); - } - else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) - { - ivas_mc2sba( st_ivas->hIntSetup, p_tc, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); - } - else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) - { - if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) +#endif + } + else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { - return error; +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_mc2sba( st_ivas->hIntSetup, p_tc, p_output, nSamplesRenderedLocal, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#else + ivas_mc2sba( st_ivas->hIntSetup, p_tc, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#endif } + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, nSamplesRenderedLocal ) ) != IVAS_ERR_OK ) +#else + if ( ( ivas_td_binaural_renderer_sf( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) +#endif + { + return error; + } +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_binaural_add_LFE( st_ivas, nSamplesRenderedLocal, p_tc, p_output ); +#else #ifdef NONBE_FIX_589_JBM_TC_OFFSETS ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_tc, p_output ); #else ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, st_ivas->hTcBuffer->tc, p_output ); #endif +#endif + } } - } #ifdef JBM_PARAMUPMIX - else if ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) - { - ivas_mc_paramupmix_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_tc, p_output ); - - /* HP filtering */ - for ( n = 0; n < st_ivas->nchan_transport; n++ ) + else if ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) { - if ( n != LFE_CHANNEL ) + ivas_mc_paramupmix_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_tc, p_output ); + + /* HP filtering */ + for ( n = 0; n < st_ivas->nchan_transport; n++ ) { - hp20( p_output[n], *nSamplesRendered, st_ivas->mem_hp20_out[n], output_Fs ); + if ( n != LFE_CHANNEL ) + { + hp20( p_output[n], *nSamplesRendered, st_ivas->mem_hp20_out[n], output_Fs ); + } } - } - if ( st_ivas->transport_config != st_ivas->intern_config && ( st_ivas->intern_config == AUDIO_CONFIG_FOA || st_ivas->intern_config == AUDIO_CONFIG_HOA2 || st_ivas->intern_config == AUDIO_CONFIG_HOA3 ) ) - { - ivas_mc2sba( st_ivas->hTransSetup, p_output, p_output, *nSamplesRendered, st_ivas->hIntSetup.ambisonics_order, GAIN_LFE ); - } + if ( st_ivas->transport_config != st_ivas->intern_config && ( st_ivas->intern_config == AUDIO_CONFIG_FOA || st_ivas->intern_config == AUDIO_CONFIG_HOA2 || st_ivas->intern_config == AUDIO_CONFIG_HOA3 ) ) + { + ivas_mc2sba( st_ivas->hTransSetup, p_output, p_output, *nSamplesRendered, st_ivas->hIntSetup.ambisonics_order, GAIN_LFE ); + } - /* Rendering */ - if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) - { - ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); - } - else if ( st_ivas->renderer_type == RENDERER_MC ) - { - ivas_ls_setup_conversion( st_ivas, MC_PARAMUPMIX_MAX_INPUT_CHANS, *nSamplesRendered, p_output, p_output ); - } - else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) - { - ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); - } - else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) - { - if ( ( ivas_td_binaural_renderer( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) + /* Rendering */ + if ( st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV || st_ivas->renderer_type == RENDERER_BINAURAL_FASTCONV_ROOM ) { - return error; + ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); + } + else if ( st_ivas->renderer_type == RENDERER_MC ) + { + ivas_ls_setup_conversion( st_ivas, MC_PARAMUPMIX_MAX_INPUT_CHANS, *nSamplesRendered, p_output, p_output ); + } + else if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) + { + ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); } + else if ( st_ivas->renderer_type == RENDERER_BINAURAL_OBJECTS_TD ) + { + if ( ( ivas_td_binaural_renderer( st_ivas, p_output, *nSamplesRendered ) ) != IVAS_ERR_OK ) + { + return error; + } - ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); + ivas_binaural_add_LFE( st_ivas, *nSamplesRendered, p_output, p_output ); + } } - } #endif - else if ( st_ivas->mc_mode == MC_MODE_PARAMMC ) - { - ivas_param_mc_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); - } - else if ( st_ivas->mc_mode == MC_MODE_MCMASA ) - { - int16_t offset = hSpatParamRendCom->slots_rendered * hSpatParamRendCom->slot_size; - nchan_remapped = st_ivas->nchan_transport; - - if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) + else if ( st_ivas->mc_mode == MC_MODE_PARAMMC ) { - ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, nchan_remapped, p_output ); +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_param_mc_dec_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, p_output ); +#else + ivas_param_mc_dec_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); +#endif } - else if ( st_ivas->renderer_type == RENDERER_DIRAC || st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) /* rendering to CICPxx and Ambisonics */ - { - ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); - - if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) +// sgi2bay: seems like this was implemented on main in the meantime (see above). Please review +// #ifdef API_5MS +// else if ( st_ivas->mc_mode == MC_MODE_PARAMUPMIX ) +// { +// /* zero output for now, not yet implemented... */ +// int16_t ch; +// #ifdef JITTER_MEM_OPTIM_RENDERING +// nSamplesRenderedLocal = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAskedLocal ); +// #else +// *nSamplesRendered = min( st_ivas->hTcBuffer->n_samples_available, nSamplesAsked ); +// #endif /* JITTER_MEM_OPTIM_RENDERING */ +// for ( ch = 0; ch < nchan_out; ch++ ) +// { +// #ifdef JITTER_MEM_OPTIM_RENDERING +// set_zero( p_output[ch], nSamplesRenderedLocal ); +// #else +// set_zero( p_output[ch], *nSamplesRendered ); +// #endif /* JITTER_MEM_OPTIM_RENDERING */ +// } +// } +// #endif /* API_5MS */ + else if ( st_ivas->mc_mode == MC_MODE_MCMASA ) + { + int16_t offset = hSpatParamRendCom->slots_rendered * hSpatParamRendCom->slot_size; + nchan_remapped = st_ivas->nchan_transport; + + if ( st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC || st_ivas->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || st_ivas->renderer_type == RENDERER_STEREO_PARAMETRIC ) { - /* we still need to copy the separate channel if available */ - if ( st_ivas->hOutSetup.separateChannelEnabled ) +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, nchan_remapped, p_output ); +#else + ivas_dirac_dec_binaural_render( st_ivas, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, nchan_remapped, p_output ); +#endif + } + else if ( st_ivas->renderer_type == RENDERER_DIRAC || st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) /* rendering to CICPxx and Ambisonics */ + { +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, &nSamplesRenderedLocal, nSamplesAvailableNext, p_output ); +#else + ivas_dirac_dec_render( st_ivas, nchan_remapped, nSamplesAskedLocal, nSamplesRendered, nSamplesAvailableNext, p_output ); +#endif + if ( st_ivas->renderer_type == RENDERER_SBA_LINEAR_ENC ) { + /* we still need to copy the separate channel if available */ + if ( st_ivas->hOutSetup.separateChannelEnabled ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], nSamplesRenderedLocal ); +#else mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], *nSamplesRendered ); - } - +#endif + } +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, nSamplesRenderedLocal, st_ivas->hOutSetup.ambisonics_order, 0.f ); +#else ivas_mc2sba( st_ivas->hIntSetup, p_output, p_output, *nSamplesRendered, st_ivas->hOutSetup.ambisonics_order, 0.f ); - } - else if ( st_ivas->intern_config == AUDIO_CONFIG_5_1 && ( output_config == AUDIO_CONFIG_5_1_2 || output_config == AUDIO_CONFIG_5_1_4 || output_config == AUDIO_CONFIG_7_1 ) ) - { - for ( n = st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; n < st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe; n++ ) +#endif + } + else if ( st_ivas->intern_config == AUDIO_CONFIG_5_1 && ( output_config == AUDIO_CONFIG_5_1_2 || output_config == AUDIO_CONFIG_5_1_4 || output_config == AUDIO_CONFIG_7_1 ) ) { + for ( n = st_ivas->hIntSetup.nchan_out_woLFE + st_ivas->hIntSetup.num_lfe; n < st_ivas->hOutSetup.nchan_out_woLFE + st_ivas->hOutSetup.num_lfe; n++ ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + set_zero( output[n], nSamplesRenderedLocal ); +#else set_zero( output[n], *nSamplesRendered ); +#endif + } } } - } - /* copy discrete C and TD LFE from internal TC to output */ - if ( st_ivas->hOutSetup.separateChannelEnabled ) - { - if ( output_config == AUDIO_CONFIG_5_1 || output_config == AUDIO_CONFIG_7_1 || - output_config == AUDIO_CONFIG_5_1_4 || output_config == AUDIO_CONFIG_7_1_4 || - output_config == AUDIO_CONFIG_5_1_2 || ( output_config == AUDIO_CONFIG_LS_CUSTOM && st_ivas->hOutSetup.num_lfe > 0 ) ) + /* copy discrete C and TD LFE from internal TC to output */ + if ( st_ivas->hOutSetup.separateChannelEnabled ) { + if ( output_config == AUDIO_CONFIG_5_1 || output_config == AUDIO_CONFIG_7_1 || + output_config == AUDIO_CONFIG_5_1_4 || output_config == AUDIO_CONFIG_7_1_4 || + output_config == AUDIO_CONFIG_5_1_2 || ( output_config == AUDIO_CONFIG_LS_CUSTOM && st_ivas->hOutSetup.num_lfe > 0 ) ) + { +#ifdef JITTER_MEM_OPTIM_RENDERING + mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL] + offset, output[LFE_CHANNEL], nSamplesRenderedLocal ); + mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], nSamplesRenderedLocal ); +#else mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL] + offset, output[LFE_CHANNEL], *nSamplesRendered ); mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], *nSamplesRendered ); - } - else if ( output_config == AUDIO_CONFIG_LS_CUSTOM && st_ivas->hOutSetup.num_lfe == 0 ) - { - /* Delay the separated channel to sync with the DirAC rendering */ +#endif + } + else if ( output_config == AUDIO_CONFIG_LS_CUSTOM && st_ivas->hOutSetup.num_lfe == 0 ) + { + /* Delay the separated channel to sync with the DirAC rendering */ +#ifdef JITTER_MEM_OPTIM_RENDERING + mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], nSamplesRenderedLocal ); +#else mvr2r( st_ivas->hTcBuffer->tc[LFE_CHANNEL - 1] + offset, output[st_ivas->hOutSetup.separateChannelIndex], *nSamplesRendered ); +#endif + } } } } - } - /*----------------------------------------------------------------* - * Write IVAS output channels - * - compensation for saturation - * - float to integer conversion - *----------------------------------------------------------------*/ + /*----------------------------------------------------------------* + * Write IVAS output channels + * - compensation for saturation + * - float to integer conversion + *----------------------------------------------------------------*/ +#ifdef JITTER_MEM_OPTIM_RENDERING + st_ivas->hTcBuffer->n_samples_available -= nSamplesRenderedLocal; + st_ivas->hTcBuffer->n_samples_rendered += nSamplesRenderedLocal; +#else st_ivas->hTcBuffer->n_samples_available -= *nSamplesRendered; st_ivas->hTcBuffer->n_samples_rendered += *nSamplesRendered; +#endif - if ( st_ivas->hTcBuffer->n_samples_discard > 0 ) - { - for ( n = 0; n < MAX_OUTPUT_CHANNELS; n++ ) + if ( st_ivas->hTcBuffer->n_samples_discard > 0 ) { - p_output[n] += st_ivas->hTcBuffer->n_samples_discard; - } + for ( n = 0; n < MAX_OUTPUT_CHANNELS; n++ ) + { + p_output[n] += st_ivas->hTcBuffer->n_samples_discard; + } +#ifdef JITTER_MEM_OPTIM_RENDERING + nSamplesRenderedLocal -= st_ivas->hTcBuffer->n_samples_discard; +#else *nSamplesRendered -= st_ivas->hTcBuffer->n_samples_discard; - st_ivas->hTcBuffer->n_samples_discard = 0; - } +#endif + st_ivas->hTcBuffer->n_samples_discard = 0; + } - ivas_limiter_dec( st_ivas->hLimiter, p_output, nchan_out, *nSamplesRendered, st_ivas->BER_detect ); +#ifndef DISABLE_LIMITER +#ifdef JITTER_MEM_OPTIM_RENDERING + ivas_limiter_dec( st_ivas->hLimiter, p_output, nchan_out, nSamplesRenderedLocal, st_ivas->BER_detect ); +#else + ivas_limiter_dec( st_ivas->hLimiter, p_output, nchan_out, *nSamplesRendered, st_ivas->BER_detect ); +#endif +#endif +#ifdef JITTER_MEM_OPTIM_RENDERING +#ifdef DEBUGGING + st_ivas->noClipping += +#endif + ivas_syn_output( p_output, nSamplesRenderedLocal, nchan_out, data + *nSamplesRendered * nchan_out ); + *nSamplesRendered += nSamplesRenderedLocal; + + st_ivas->hTcBuffer->subframes_rendered = subframes_rendered + 1; + } +#else #ifdef DEBUGGING st_ivas->noClipping += #endif ivas_syn_output( p_output, *nSamplesRendered, nchan_out, data ); - +#endif *nSamplesAvailableNext = st_ivas->hTcBuffer->n_samples_available; pop_wmops(); @@ -1541,6 +1800,12 @@ int16_t ivas_jbm_dec_get_num_tc_channels( } } } +#ifdef API_5MS + else if ( st_ivas->ivas_format == MONO_FORMAT && st_ivas->renderer_type == RENDERER_NON_DIEGETIC_DOWNMIX ) + { + num_tc = MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN; + } +#endif return num_tc; } @@ -1599,6 +1864,9 @@ static void ivas_jbm_dec_copy_tc( } hTcBuffer->n_samples_rendered = 0; +#ifdef API_5MS + hTcBuffer->subframes_rendered = 0; +#endif return; } @@ -1723,34 +1991,66 @@ ivas_error ivas_jbm_dec_tc_buffer_open( } else { +#ifdef API_5MS + int16_t n_samp_full, n_samp_residual; +#else int16_t n_samp_full = ( NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ) + hTcBuffer->n_samples_granularity - 1 ); int16_t n_samp_residual = hTcBuffer->n_samples_granularity - 1; +#endif int32_t offset; - - nsamp_to_allocate = hTcBuffer->nchan_buffer_full * n_samp_full; - nsamp_to_allocate += nchan_residual * n_samp_residual; - - if ( ( hTcBuffer->tc_buffer = (float *) malloc( nsamp_to_allocate * sizeof( float ) ) ) == NULL ) +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) { - return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); + n_samp_full = ( NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ) + hTcBuffer->n_samples_granularity - 1 ); + n_samp_residual = hTcBuffer->n_samples_granularity - 1; } - set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); - - offset = 0; - for ( ch_idx = 0; ch_idx < hTcBuffer->nchan_buffer_full; ch_idx++ ) + else { - hTcBuffer->tc[ch_idx] = &hTcBuffer->tc_buffer[offset]; - offset += n_samp_full; + n_samp_full = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); + n_samp_residual = 0; } - for ( ; ch_idx < hTcBuffer->nchan_transport_internal; ch_idx++ ) +#endif + + + nsamp_to_allocate = hTcBuffer->nchan_buffer_full * n_samp_full; + nsamp_to_allocate += nchan_residual * n_samp_residual; + +#ifdef API_5MS + if ( nsamp_to_allocate == 0 ) { - hTcBuffer->tc[ch_idx] = &hTcBuffer->tc_buffer[offset]; - offset += n_samp_residual; + hTcBuffer->tc_buffer = NULL; + for ( ch_idx = 0; ch_idx < MAX_TRANSPORT_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = NULL; + } } - for ( ; ch_idx < MAX_TRANSPORT_CHANNELS; ch_idx++ ) + else { - hTcBuffer->tc[ch_idx] = NULL; +#endif + if ( ( hTcBuffer->tc_buffer = (float *) malloc( nsamp_to_allocate * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM TC Buffer\n" ) ); + } + set_zero( hTcBuffer->tc_buffer, nsamp_to_allocate ); + + offset = 0; + for ( ch_idx = 0; ch_idx < hTcBuffer->nchan_buffer_full; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = &hTcBuffer->tc_buffer[offset]; + offset += n_samp_full; + } + for ( ; ch_idx < hTcBuffer->nchan_transport_internal; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = &hTcBuffer->tc_buffer[offset]; + offset += n_samp_residual; + } + for ( ; ch_idx < MAX_TRANSPORT_CHANNELS; ch_idx++ ) + { + hTcBuffer->tc[ch_idx] = NULL; + } +#ifdef API_5MS } +#endif } st_ivas->hTcBuffer = hTcBuffer; @@ -1829,8 +2129,21 @@ ivas_error ivas_jbm_dec_tc_buffer_reconfigure( /* realloc buffers */ free( hTcBuffer->tc_buffer ); +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) + { + n_samp_full = ( NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ) + hTcBuffer->n_samples_granularity - 1 ); + n_samp_residual = hTcBuffer->n_samples_granularity - 1; + } + else + { + n_samp_full = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); + n_samp_residual = 0; + } +#else n_samp_full = ( NS2SA( st_ivas->hDecoderConfig->output_Fs, MAX_JBM_L_FRAME_NS ) + hTcBuffer->n_samples_granularity - 1 ); n_samp_residual = hTcBuffer->n_samples_granularity - 1; +#endif nsamp_to_allocate = hTcBuffer->nchan_buffer_full * n_samp_full; nsamp_to_allocate += nchan_residual * n_samp_residual; @@ -2012,9 +2325,24 @@ TC_BUFFER_MODE ivas_jbm_dec_get_tc_buffer_mode( case RENDERER_PARAM_ISM: case RENDERER_BINAURAL_MIXER_CONV: case RENDERER_BINAURAL_MIXER_CONV_ROOM: +#ifdef API_5MS + buffer_mode = TC_BUFFER_MODE_RENDERER; + break; + case RENDERER_NON_DIEGETIC_DOWNMIX: + if ( st_ivas->ivas_format == MONO_FORMAT ) + { + buffer_mode = TC_BUFFER_MODE_BUFFER; + } + else + { + buffer_mode = TC_BUFFER_MODE_RENDERER; + } + break; +#else case RENDERER_NON_DIEGETIC_DOWNMIX: buffer_mode = TC_BUFFER_MODE_RENDERER; break; +#endif case RENDERER_MC_PARAMMC: if ( st_ivas->hParamMC->synthesis_conf == PARAM_MC_SYNTH_MONO_STEREO ) { @@ -2060,6 +2388,76 @@ TC_BUFFER_MODE ivas_jbm_dec_get_tc_buffer_mode( return buffer_mode; } +#ifdef API_5MS +void ivas_jbm_dec_copy_tc_no_tsm( + Decoder_Struct *st_ivas, + float *tc[], + const int16_t output_frame ) +{ + int16_t n_ch_full_copy; + int16_t n_ch_cldfb; + int16_t ch_idx; + DECODER_TC_BUFFER_HANDLE hTcBuffer; + + hTcBuffer = st_ivas->hTcBuffer; + hTcBuffer->n_samples_buffered = output_frame; + hTcBuffer->n_samples_available = hTcBuffer->n_samples_buffered; + n_ch_full_copy = min( hTcBuffer->nchan_transport_jbm, hTcBuffer->nchan_buffer_full ); + n_ch_cldfb = hTcBuffer->nchan_transport_jbm - hTcBuffer->nchan_buffer_full; + /* copy full tcs*/ + for ( ch_idx = 0; ch_idx < n_ch_full_copy; ch_idx++ ) + { + mvr2r( tc[ch_idx], st_ivas->hTcBuffer->tc[ch_idx], hTcBuffer->n_samples_buffered ); + } + + /* CLDFB ana for ParamMC/ParamISM */ + if ( n_ch_cldfb > 0 ) + { + float *cldfb_real_buffer; + float *cldfb_imag_buffer; + int16_t cldfb_ch, slot_idx, num_freq_bands; + + cldfb_real_buffer = NULL; + cldfb_imag_buffer = NULL; + num_freq_bands = 0; + + if ( st_ivas->ivas_format == ISM_FORMAT ) + { + cldfb_real_buffer = st_ivas->hDirAC->hParamIsmRendering->Cldfb_RealBuffer_tc; + cldfb_imag_buffer = st_ivas->hDirAC->hParamIsmRendering->Cldfb_ImagBuffer_tc; + num_freq_bands = st_ivas->hSpatParamRendCom->num_freq_bands; + ivas_ism_param_dec_tc_gain_ajust( st_ivas, output_frame, output_frame / 2, tc ); + } + else if ( st_ivas->ivas_format == MC_FORMAT ) + { + cldfb_real_buffer = st_ivas->hParamMC->Cldfb_RealBuffer_tc; + cldfb_imag_buffer = st_ivas->hParamMC->Cldfb_ImagBuffer_tc; + num_freq_bands = st_ivas->hParamMC->num_freq_bands; + } +#ifdef DEBUGGING + else + { + assert( 0 && "Residual (direct CLDFB transport channels) only possible for ParamMC/ParamISM!" ); + } +#endif + /* CLDFB Analysis*/ + + for ( cldfb_ch = 0; cldfb_ch < n_ch_cldfb; cldfb_ch++, ch_idx++ ) + { + for ( slot_idx = 0; slot_idx < DEFAULT_JBM_CLDFB_TIMESLOTS; slot_idx++ ) + { + cldfbAnalysis_ts( &( tc[ch_idx][num_freq_bands * slot_idx] ), + &cldfb_real_buffer[slot_idx * num_freq_bands * n_ch_cldfb + cldfb_ch * num_freq_bands], + &cldfb_imag_buffer[slot_idx * num_freq_bands * n_ch_cldfb + cldfb_ch * num_freq_bands], + num_freq_bands, st_ivas->cldfbAnaDec[cldfb_ch] ); + } + } + } + hTcBuffer->n_samples_rendered = 0; + hTcBuffer->subframes_rendered = 0; +} +#endif + #ifdef FIX_470_MASA_JBM_EXT /*--------------------------------------------------------------------------* diff --git a/lib_dec/ivas_masa_dec.c b/lib_dec/ivas_masa_dec.c index 4a6053ccd5b44aa3ccf191ecb847ed553d4eea41..b686b0431bd891a01aa7f354959a7434f434f41e 100644 --- a/lib_dec/ivas_masa_dec.c +++ b/lib_dec/ivas_masa_dec.c @@ -385,7 +385,11 @@ ivas_error ivas_masa_dec_open( st_ivas->hMasa = hMasa; /* allocate transport channels*/ +#ifdef API_5MS + if ( st_ivas->hTcBuffer == NULL && st_ivas->renderer_type != RENDERER_DISABLE && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC_ROOM && st_ivas->renderer_type != RENDERER_STEREO_PARAMETRIC ) +#else if ( st_ivas->hDecoderConfig->voip_active == 1 && st_ivas->hTcBuffer == NULL && st_ivas->renderer_type != RENDERER_DISABLE && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC && st_ivas->renderer_type != RENDERER_BINAURAL_PARAMETRIC_ROOM && st_ivas->renderer_type != RENDERER_STEREO_PARAMETRIC ) +#endif { int16_t nchan_to_allocate; TC_BUFFER_MODE buffer_mode; @@ -1089,7 +1093,9 @@ ivas_error ivas_masa_dec_reconfigure( ivas_masa_set_elements( ivas_total_brate, st_ivas->mc_mode, st_ivas->nchan_transport, st_ivas->hQMetaData, &tmp, &tmp, &tmp ); +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active == 1 ) +#endif { int16_t tc_nchan_to_allocate; int16_t tc_nchan_transport; diff --git a/lib_dec/ivas_mc_param_dec.c b/lib_dec/ivas_mc_param_dec.c index 0ba001d415aee165d188879bcfa20bf787f76ae0..b2b3625d0551065b5685fa220ca1e3084a3fa339 100644 --- a/lib_dec/ivas_mc_param_dec.c +++ b/lib_dec/ivas_mc_param_dec.c @@ -459,8 +459,32 @@ ivas_error ivas_param_mc_dec_open( ivas_param_mc_dec_init( hParamMC, nchan_transport, nchan_out_cov ); +#ifdef API_5MS + if ( hParamMC->synthesis_conf != PARAM_MC_SYNTH_MONO_STEREO ) +#else if ( st_ivas->hDecoderConfig->voip_active && hParamMC->synthesis_conf != PARAM_MC_SYNTH_MONO_STEREO ) +#endif { +#ifdef API_5MS + int16_t n_cldfb_slots; + + n_cldfb_slots = DEFAULT_JBM_CLDFB_TIMESLOTS; + if ( st_ivas->hDecoderConfig->tsm_active ) + { + n_cldfb_slots = MAX_JBM_CLDFB_TIMESLOTS; + } + if ( ( hParamMC->Cldfb_RealBuffer_tc = (float *) malloc( n_cldfb_slots * nchan_transport * hParamMC->num_freq_bands * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Parametric MC JBM\n" ) ); + } + set_zero( hParamMC->Cldfb_RealBuffer_tc, n_cldfb_slots * nchan_transport * hParamMC->num_freq_bands ); + + if ( ( hParamMC->Cldfb_ImagBuffer_tc = (float *) malloc( n_cldfb_slots * nchan_transport * hParamMC->num_freq_bands * sizeof( float ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Parametric MC JBM\n" ) ); + } + set_zero( hParamMC->Cldfb_ImagBuffer_tc, n_cldfb_slots * nchan_transport * hParamMC->num_freq_bands ); +#else if ( ( hParamMC->Cldfb_RealBuffer_tc = (float *) malloc( MAX_JBM_CLDFB_TIMESLOTS * nchan_transport * hParamMC->num_freq_bands * sizeof( float ) ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Parametric MC JBM\n" ) ); @@ -472,7 +496,7 @@ ivas_error ivas_param_mc_dec_open( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Parametric MC JBM\n" ) ); } set_zero( hParamMC->Cldfb_ImagBuffer_tc, MAX_JBM_CLDFB_TIMESLOTS * nchan_transport * hParamMC->num_freq_bands ); - +#endif if ( st_ivas->hTcBuffer == NULL ) { if ( ( error = ivas_jbm_dec_tc_buffer_open( st_ivas, TC_BUFFER_MODE_RENDERER, nchan_transport, nchan_transport, 0, NS2SA( st_ivas->hDecoderConfig->output_Fs, CLDFB_SLOT_NS ) ) ) != IVAS_ERR_OK ) @@ -1451,6 +1475,10 @@ void ivas_param_mc_dec_digest_tc( hParamMC->slots_rendered = 0; hParamMC->subframes_rendered = 0; ivas_jbm_dec_get_adapted_subframes( nCldfbSlots, hParamMC->subframe_nbslots, &hParamMC->nb_subframes ); +#ifdef API_5MS + st_ivas->hTcBuffer->nb_subframes = hParamMC->nb_subframes; + mvs2s( hParamMC->subframe_nbslots, st_ivas->hTcBuffer->subframe_nbslots, hParamMC->nb_subframes ); +#endif ivas_param_mc_dec_compute_interpolator( hParamMC->hMetadataPMC->bAttackPresent, hParamMC->hMetadataPMC->attackIndex, nCldfbSlots, hParamMC->h_output_synthesis_params.interpolator ); @@ -1463,18 +1491,24 @@ void ivas_param_mc_dec_digest_tc( /* slot loop for gathering the input data */ for ( slot_idx = 0; slot_idx < nCldfbSlots; slot_idx++ ) { - float RealBuffer[CLDFB_NO_CHANNELS_MAX]; - float ImagBuffer[CLDFB_NO_CHANNELS_MAX]; - - /* CLDFB Analysis*/ - for ( ch = 0; ch < nchan_transport; ch++ ) +#ifdef API_5MS + if ( st_ivas->hDecoderConfig->tsm_active ) { - cldfbAnalysis_ts( &( transport_channels_f[ch][hParamMC->num_freq_bands * slot_idx] ), RealBuffer, ImagBuffer, hParamMC->num_freq_bands, st_ivas->cldfbAnaDec[ch] ); +#endif + float RealBuffer[CLDFB_NO_CHANNELS_MAX]; + float ImagBuffer[CLDFB_NO_CHANNELS_MAX]; - mvr2r( RealBuffer, &hParamMC->Cldfb_RealBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport + ch * hParamMC->num_freq_bands], hParamMC->num_freq_bands ); - mvr2r( ImagBuffer, &hParamMC->Cldfb_ImagBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport + ch * hParamMC->num_freq_bands], hParamMC->num_freq_bands ); - } + /* CLDFB Analysis*/ + for ( ch = 0; ch < nchan_transport; ch++ ) + { + cldfbAnalysis_ts( &( transport_channels_f[ch][hParamMC->num_freq_bands * slot_idx] ), RealBuffer, ImagBuffer, hParamMC->num_freq_bands, st_ivas->cldfbAnaDec[ch] ); + mvr2r( RealBuffer, &hParamMC->Cldfb_RealBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport + ch * hParamMC->num_freq_bands], hParamMC->num_freq_bands ); + mvr2r( ImagBuffer, &hParamMC->Cldfb_ImagBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport + ch * hParamMC->num_freq_bands], hParamMC->num_freq_bands ); + } +#ifdef API_5MS + } +#endif if ( slot_idx >= 2 * hParamMC->hMetadataPMC->attackIndex ) { ivas_dirac_dec_output_synthesis_cov_param_mc_collect_slot( &hParamMC->Cldfb_RealBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport], &hParamMC->Cldfb_ImagBuffer_tc[slot_idx * hParamMC->num_freq_bands * nchan_transport], cx, cx_imag, hParamMC, nchan_transport ); @@ -1536,11 +1570,11 @@ void ivas_param_mc_dec_digest_tc( *------------------------------------------------------------------------*/ void ivas_param_mc_dec_render( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ - const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ - uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ - uint16_t *nSamplesAvailable, /* o : number of CLDFB slots still to render */ - float *output_f[] /* o : rendered time signal */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ + uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ + uint16_t *nSamplesAvailableNext, /* o : number of CLDFB slots still to render */ + float *output_f[] /* o : rendered time signal */ ) { PARAM_MC_DEC_HANDLE hParamMC; @@ -1758,15 +1792,18 @@ void ivas_param_mc_dec_render( #ifdef SPLIT_REND_WITH_HEAD_ROT &st_ivas->splitBinRend.splitrend.multiBinPoseData, #endif - st_ivas->hCombinedOrientationData, subframe_idx, - hParamMC->subframe_nbslots[subframe_idx], - #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG NULL, #endif + st_ivas->hCombinedOrientationData, +#ifndef API_5MS + subframe_idx, +#endif + hParamMC->subframe_nbslots[subframe_idx], + Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, Cldfb_RealBuffer, Cldfb_ImagBuffer ); -#ifdef SPLIT_REND_WITH_HEAD_ROT +#ifdef SPLIT_REND_WITH_HEAD_ROT if ( ( st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || ( st_ivas->hDecoderConfig->output_config == AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) { @@ -1842,7 +1879,7 @@ void ivas_param_mc_dec_render( param_mc_update_mixing_matrices( hParamMC, hParamMC->h_output_synthesis_cov_state.mixing_matrix, hParamMC->h_output_synthesis_cov_state.mixing_matrix_res, nchan_transport, nchan_out_cov ); } hParamMC->subframes_rendered = last_sf; - *nSamplesAvailable = ( hParamMC->num_slots - hParamMC->slots_rendered ) * NS2SA( output_Fs, CLDFB_SLOT_NS ); + *nSamplesAvailableNext = ( hParamMC->num_slots - hParamMC->slots_rendered ) * NS2SA( output_Fs, CLDFB_SLOT_NS ); pop_wmops(); return; @@ -1863,7 +1900,7 @@ void ivas_param_mc_dec( PARAM_MC_DEC_HANDLE hParamMC; float Cldfb_RealBuffer_in[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_NSLOTS * CLDFB_NO_CHANNELS_MAX]; float Cldfb_ImagBuffer_in[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_NSLOTS * CLDFB_NO_CHANNELS_MAX]; - uint16_t nSamplesAsked, nSamplesAvailable, nSamplesRendered; + uint16_t nSamplesAsked, nSamplesAvailableNext, nSamplesRendered; hParamMC = st_ivas->hParamMC; assert( hParamMC ); @@ -1875,10 +1912,10 @@ void ivas_param_mc_dec( nSamplesAsked = (int16_t) ( st_ivas->hDecoderConfig->output_Fs / FRAMES_PER_SEC ); ivas_param_mc_dec_digest_tc( st_ivas, DEFAULT_JBM_CLDFB_TIMESLOTS, output_f ); - ivas_param_mc_dec_render( st_ivas, nSamplesAsked, &nSamplesRendered, &nSamplesAvailable, output_f ); + ivas_param_mc_dec_render( st_ivas, nSamplesAsked, &nSamplesRendered, &nSamplesAvailableNext, output_f ); #ifdef DEBUGGING assert( nSamplesRendered == nSamplesAsked ); - assert( nSamplesAvailable == 0 ); + assert( nSamplesAvailableNext == 0 ); #endif /* set handle pointers back to NULL */ diff --git a/lib_dec/ivas_mc_paramupmix_dec.c b/lib_dec/ivas_mc_paramupmix_dec.c index 9ae580ae3a07a06a34721ba4495287088b54e326..02f663f66876e14e25a0feb1ad2d971572b703b5 100644 --- a/lib_dec/ivas_mc_paramupmix_dec.c +++ b/lib_dec/ivas_mc_paramupmix_dec.c @@ -491,7 +491,13 @@ ivas_error ivas_mc_paramupmix_dec_open( /* allocate transport channels*/ hMCParamUpmix->free_param_interpolator = 0; hMCParamUpmix->param_interpolator = NULL; - if ( st_ivas->hDecoderConfig->voip_active == 1 && st_ivas->hTcBuffer == NULL ) + if ( +#ifdef API_5MS + st_ivas->hDecoderConfig->tsm_active == 1 +#else + st_ivas->hDecoderConfig->voip_active == 1 +#endif + && st_ivas->hTcBuffer == NULL ) { int16_t nchan_to_allocate; int16_t nchan_tc; diff --git a/lib_dec/ivas_mct_dec.c b/lib_dec/ivas_mct_dec.c index e99cf63fa64376f9ab08878e7d95380cc2f284d8..578a010ae192441bce3d4f1a8ea7cce62bd1d29e 100755 --- a/lib_dec/ivas_mct_dec.c +++ b/lib_dec/ivas_mct_dec.c @@ -726,7 +726,9 @@ static ivas_error ivas_mc_dec_reconfig( /* side effect of the renderer selection can be a changed internal config */ ivas_output_init( &( st_ivas->hIntSetup ), st_ivas->intern_config ); +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active ) +#endif { /* transfer subframe info from DirAC or ParamMC to central tc buffer */ if ( last_mc_mode == MC_MODE_PARAMMC ) @@ -1260,8 +1262,9 @@ static ivas_error ivas_mc_dec_reconfig( /*-----------------------------------------------------------------* * Reconfigure TC buffer *-----------------------------------------------------------------*/ - +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active == 1 ) +#endif { int16_t tc_nchan_full_new; DECODER_TC_BUFFER_HANDLE hTcBuffer; diff --git a/lib_dec/ivas_objectRenderer_internal.c b/lib_dec/ivas_objectRenderer_internal.c index 3be8a2c62ebfdf1c46806b276c8a7a0c8a54b23d..567a91f4fb37daabfe10ede6a3f4da115550a041 100644 --- a/lib_dec/ivas_objectRenderer_internal.c +++ b/lib_dec/ivas_objectRenderer_internal.c @@ -86,10 +86,21 @@ ivas_error ivas_td_binaural_renderer( st_ivas->transport_config, st_ivas->hBinRendererTd, st_ivas->nchan_transport, LFE_CHANNEL, st_ivas->ivas_format, st_ivas->hIsmMetaData, +#ifdef API_5MS + ( st_ivas->hCombinedOrientationData != NULL ) ? &st_ivas->hCombinedOrientationData->enableCombinedOrientation : NULL, + ( st_ivas->hCombinedOrientationData != NULL ) ? &st_ivas->hCombinedOrientationData->Quaternion : NULL, + ( st_ivas->hCombinedOrientationData != NULL ) ? &st_ivas->hCombinedOrientationData->listenerPos : NULL, +#else ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->enableCombinedOrientation : NULL, ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->Quaternions : NULL, ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->listenerPos : NULL, - ism_md_subframe_update, output, output_frame ); +#endif + ism_md_subframe_update, output, output_frame +#ifdef LIB_REND_API_5MS + , + MAX_PARAM_SPATIAL_SUBFRAMES +#endif + ); } @@ -178,10 +189,17 @@ ivas_error ivas_td_binaural_renderer_sf( } /* Update the listener's location/orientation */ +#ifdef API_5MS + TDREND_Update_listener_orientation( st_ivas->hBinRendererTd, + ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->enableCombinedOrientation : 0, + ( st_ivas->hCombinedOrientationData != NULL ) ? &st_ivas->hCombinedOrientationData->Quaternion : NULL, + ( st_ivas->hCombinedOrientationData != NULL ) ? &st_ivas->hCombinedOrientationData->listenerPos : NULL ); +#else TDREND_Update_listener_orientation( st_ivas->hBinRendererTd, ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->enableCombinedOrientation[subframe_idx] : 0, ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->Quaternions : NULL, ( st_ivas->hCombinedOrientationData != NULL ) ? st_ivas->hCombinedOrientationData->listenerPos : NULL ); +#endif if ( st_ivas->hRenderConfig != NULL && st_ivas->hIntSetup.output_config == AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) { @@ -192,7 +210,7 @@ ivas_error ivas_td_binaural_renderer_sf( } /* Render subframe */ - if ( ( error = TDREND_GetMix( st_ivas->hBinRendererTd, output_f_local, output_frame, 0, ism_md_subframe_update_jbm ) ) != IVAS_ERR_OK ) + if ( ( error = TDREND_GetMix( st_ivas->hBinRendererTd, output_f_local, output_frame, 0, ism_md_subframe_update_jbm != subframe_idx ) ) != IVAS_ERR_OK ) { return error; } diff --git a/lib_dec/ivas_output_config.c b/lib_dec/ivas_output_config.c index abc9a9012dfe0b90e81193ce49f12716626a2834..01dfa0f44a69c3103a842a8aa819582dda8e2015 100644 --- a/lib_dec/ivas_output_config.c +++ b/lib_dec/ivas_output_config.c @@ -518,7 +518,18 @@ void ivas_set_split_rend_setup( IVAS_DEC_SPLIT_REND_WRAPPER *hSplitBinRend, IVAS if ( ( hCombinedOrientationData != NULL ) && ( hSplitBinRend->splitrend.multiBinPoseData.poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) ) { - int16_t sf, i, j; + int16_t i, j; +#ifdef API_5MS + hCombinedOrientationData->Quaternion = hCombinedOrientationData->Quaternion; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + hCombinedOrientationData->Rmat[i][j] = hCombinedOrientationData->Rmat[i][j]; + } + } +#else + int16_t sf; for ( sf = 1; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ ) { hCombinedOrientationData->Quaternions[sf] = hCombinedOrientationData->Quaternions[0]; @@ -530,6 +541,7 @@ void ivas_set_split_rend_setup( IVAS_DEC_SPLIT_REND_WRAPPER *hSplitBinRend, IVAS } } } +#endif } return; diff --git a/lib_dec/ivas_sba_dec.c b/lib_dec/ivas_sba_dec.c index 763a1b222fde2f2c596e3f0239a9ea812788475c..32a0955bfadd981fd78964764a1295f5133fca9b 100755 --- a/lib_dec/ivas_sba_dec.c +++ b/lib_dec/ivas_sba_dec.c @@ -378,7 +378,9 @@ ivas_error ivas_sba_dec_reconfigure( * JBM TC buffer *-----------------------------------------------------------------*/ +#ifndef API_5MS if ( st_ivas->hDecoderConfig->voip_active == 1 ) +#endif { int16_t tc_nchan_to_allocate; int16_t tc_nchan_tc; @@ -499,11 +501,11 @@ ivas_error ivas_sba_dec_digest_tc( *-------------------------------------------------------------------*/ void ivas_sba_dec_render( - Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ - const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ - uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ - uint16_t *nSamplesAvailable, /* o : number of CLDFB slots still to render */ - float *output_f[] /* o : rendered time signal */ + Decoder_Struct *st_ivas, /* i/o: IVAS decoder handle */ + const uint16_t nSamplesAsked, /* i : number of CLDFB slots requested */ + uint16_t *nSamplesRendered, /* o : number of CLDFB slots rendered */ + uint16_t *nSamplesAvailableNext, /* o : number of CLDFB slots still to render */ + float *output_f[] /* o : rendered time signal */ ) { int16_t slots_to_render, first_sf, last_sf, subframe_idx; @@ -571,7 +573,7 @@ void ivas_sba_dec_render( } } - *nSamplesAvailable = ( hSpar->num_slots - hSpar->slots_rendered ) * slot_size; + *nSamplesAvailableNext = ( hSpar->num_slots - hSpar->slots_rendered ) * slot_size; return; } diff --git a/lib_dec/ivas_sba_rendering_internal.c b/lib_dec/ivas_sba_rendering_internal.c index 643c7b5a6c2146f49bcab96c21cf047bec9e4b1d..18b5db2f3dda47656614a0bd28f634d98b971cb1 100644 --- a/lib_dec/ivas_sba_rendering_internal.c +++ b/lib_dec/ivas_sba_rendering_internal.c @@ -365,15 +365,22 @@ void ivas_ism2sba_sf( for ( j = 0; j < sba_num_chans; j++ ) { g2 = hIsmRendererData->interpolator + offset; +#ifndef FIX_XXX_ISM_SBA_ASAN g1 = 1 - *g2; +#endif tc = buffer_in[i] + offset; out = buffer_out[j]; gain = hIsmRendererData->gains[i][j]; prev_gain = hIsmRendererData->prev_gains[i][j]; for ( k = 0; k < n_samples_to_render; k++ ) { +#ifdef FIX_XXX_ISM_SBA_ASAN + g1 = 1.0f - *g2; +#endif *( out++ ) += ( ( *( g2++ ) ) * gain + g1 * prev_gain ) * ( *( tc++ ) ); +#ifndef FIX_XXX_ISM_SBA_ASAN g1 = 1.0f - *g2; +#endif } } } diff --git a/lib_dec/ivas_spar_decoder.c b/lib_dec/ivas_spar_decoder.c index 1c839316e52fefb4ad4f4e44bc7d7533cd95efe8..f13557fcc91ad1baf33b230d8b9d2938332e9069 100644 --- a/lib_dec/ivas_spar_decoder.c +++ b/lib_dec/ivas_spar_decoder.c @@ -218,7 +218,11 @@ ivas_error ivas_spar_dec_open( } /* allocate transport channels*/ +#ifdef API_5MS + if ( st_ivas->hTcBuffer == NULL ) +#else if ( st_ivas->hDecoderConfig->voip_active == 1 && st_ivas->hTcBuffer == NULL ) +#endif { int16_t nchan_to_allocate; int16_t nchan_tc; @@ -1178,6 +1182,10 @@ void ivas_spar_dec_set_render_map( hSpar->subframes_rendered = 0; set_s( hSpar->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME ); ivas_jbm_dec_get_adapted_subframes( nCldfbTs, hSpar->subframe_nbslots, &hSpar->nb_subframes ); +#ifdef API_5MS + st_ivas->hTcBuffer->nb_subframes = hSpar->nb_subframes; + mvs2s( hSpar->subframe_nbslots, st_ivas->hTcBuffer->subframe_nbslots, hSpar->nb_subframes ); +#endif ivas_jbm_dec_get_md_map( DEFAULT_JBM_CLDFB_TIMESLOTS, nCldfbTs, 1, 0, DEFAULT_JBM_CLDFB_TIMESLOTS, hSpar->render_to_md_map ); return; diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index 5c70409ac2892ff9da3cd11cb968662475c17784..6ce7e3bb1e18a7a6ccee9284efa692d5be9405a3 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -865,7 +865,11 @@ typedef struct decoder_config_structure #ifdef DEBUGGING int16_t force_rend; /* forced TD/CLDFB binaural renderer (for ISM and MC) */ #endif +#ifdef API_5MS + int16_t tsm_active; +#else int16_t voip_active; +#endif int16_t Opt_delay_comp; /* flag indicating delay compensation active */ } DECODER_CONFIG, *DECODER_CONFIG_HANDLE; diff --git a/lib_dec/jbm_jb4sb.h b/lib_dec/jbm_jb4sb.h index 00f5ccbb4078ab61d69873fb1cd6c3e25f5128a6..599730975da23f620c190baeafe7062160192ef0 100644 --- a/lib_dec/jbm_jb4sb.h +++ b/lib_dec/jbm_jb4sb.h @@ -77,13 +77,13 @@ struct JB4_DATAUNIT int16_t partialCopyOffset; int16_t nextCoderType; }; - +#ifndef API_5MS typedef enum { JBM_RENDERER_NONE, JBM_RENDERER_IVAS, } JBM_RENDERER_TYPE; - +#endif typedef struct JB4_DATAUNIT *JB4_DATAUNIT_HANDLE; diff --git a/lib_dec/jbm_pcmdsp_fifo.c b/lib_dec/jbm_pcmdsp_fifo.c index a3e893646442922769dcbccb395f3dd9d21f8c4f..ad0a860944623ba10822f7c8565d79c17c378408 100644 --- a/lib_dec/jbm_pcmdsp_fifo.c +++ b/lib_dec/jbm_pcmdsp_fifo.c @@ -38,6 +38,7 @@ #include #include "options.h" +#ifndef API_5MS #include "prot.h" #include "ivas_prot.h" #ifdef DEBUGGING @@ -267,3 +268,4 @@ uint16_t pcmdsp_fifo_nReadableSamplesPerChannel( { return h->size; } +#endif diff --git a/lib_dec/jbm_pcmdsp_fifo.h b/lib_dec/jbm_pcmdsp_fifo.h index b601cc2e0e0001aba14c562a3b36f3447e124e27..62ebc15d08b46bb812845743f3da13461a196576 100644 --- a/lib_dec/jbm_pcmdsp_fifo.h +++ b/lib_dec/jbm_pcmdsp_fifo.h @@ -41,7 +41,7 @@ #include #include "options.h" - +#ifndef API_5MS /** Ringbuffer (FIFO) with fixed capacity for audio samples. */ struct PCMDSP_FIFO @@ -81,5 +81,5 @@ int16_t pcmdsp_fifo_write_zero( PCMDSP_FIFO_HANDLE h, uint16_t nSamplesPerChanne int16_t pcmdsp_fifo_read( PCMDSP_FIFO_HANDLE h, uint16_t nSamplesPerChannel, uint8_t *samples ); uint16_t pcmdsp_fifo_nReadableSamplesPerChannel( const PCMDSP_FIFO_HANDLE h ); - +#endif #endif /* JBM_PCMDSP_FIFO_H */ diff --git a/lib_dec/lib_dec.c b/lib_dec/lib_dec.c index 686a4b6da76eec1610cc50c681c95b682f7114f1..75dc13f5978963f332f3a46715dcaa351ce9122f 100644 --- a/lib_dec/lib_dec.c +++ b/lib_dec/lib_dec.c @@ -56,11 +56,16 @@ struct IVAS_DEC_VOIP { uint16_t nSamplesFrame; /* Total number of samples in a frame (includes number of channels) */ JB4_HANDLE hJBM; +#ifndef API_5MS PCMDSP_APA_HANDLE hTimeScaler; +#endif uint16_t lastDecodedWasActive; - float *apaExecBuffer; /* Buffer for APA scaling */ +#ifndef API_5MS + float *apaExecBuffer; /* Buffer for APA scaling */ +#endif JB4_DATAUNIT_HANDLE hCurrentDataUnit; /* Points to the currently processed data unit */ uint16_t *bs_conversion_buf; /* Buffer for bitstream conversion from packed to serial */ +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING IVAS_DEC_VOIP_MODE voipMode; uint16_t speedFac; @@ -70,6 +75,7 @@ struct IVAS_DEC_VOIP PCMDSP_FIFO_HANDLE hFifoOut; uint8_t nTransportChannelsOld; uint16_t nSamplesAvailableNext; +#endif #ifdef SUPPORT_JBM_TRACEFILE IVAS_JBM_TRACE_DATA JbmTraceData; #endif @@ -87,8 +93,19 @@ struct IVAS_DEC bool hasDecodedFirstGoodFrame; /* False on init. Gets set to true after first good frame has been decoded -> all bitstream information is known from that point on */ bool isInitialized; - int16_t bitstreamformat; /* Bitstream format flag (G.192/MIME/VOIP_G192_RTP/VOIP_RTPDUMP) */ - bool Opt_VOIP; /* flag indicating VOIP mode with JBM */ + int16_t bitstreamformat; /* Bitstream format flag (G.192/MIME/VOIP_G192_RTP/VOIP_RTPDUMP) */ + bool Opt_VOIP; /* flag indicating VOIP mode with JBM */ +#ifdef API_5MS + int16_t tsm_scale; /* scale for TSM operation */ + int16_t tsm_max_scaling; + float *apaExecBuffer; /* Buffer for APA scaling */ + PCMDSP_APA_HANDLE hTimeScaler; + bool needNewFrame; + bool hasBeenFedFrame; + uint16_t nSamplesAvailableNext; + int16_t nSamplesRendered; + int16_t nTransportChannelsOld; +#endif int16_t amrwb_rfc4867_flag; /* MIME from rfc4867 is used */ int16_t sdp_hf_only; /* RTP payload format parameter: only Header-Full format without zero padding for size collision avoidance */ int16_t prev_ft_speech; /* RXDTX handler: previous frametype flag for G.192 format AMRWB SID_FIRST detection */ @@ -108,8 +125,10 @@ static ivas_error evs_dec_main( Decoder_Struct *st_ivas, const int16_t nOutSampl static ivas_error input_format_API_to_internal( IVAS_DEC_INPUT_FORMAT input_format, int16_t *bitstream_format_internal, int16_t *sdp_hf_only, const bool is_voip_enabled ); static void init_decoder_config( DECODER_CONFIG_HANDLE hDecoderConfig ); static int16_t IVAS_DEC_VoIP_GetRenderGranularity( Decoder_Struct *st_ivas ); +#ifndef API_5MS static JBM_RENDERER_TYPE IVAS_DEC_VoIP_GetRendererConfig( IVAS_DEC_HANDLE hIvasDec ); -static ivas_error IVAS_DEC_VoIP_reconfigure( IVAS_DEC_HANDLE hIvasDec, const uint16_t nTransportChannels, const uint16_t l_ts ); +#endif +static ivas_error IVAS_DEC_reconfigure( IVAS_DEC_HANDLE hIvasDec, const uint16_t nTransportChannels, const uint16_t l_ts ); static ivas_error IVAS_DEC_Setup( IVAS_DEC_HANDLE hIvasDec, uint16_t *nTcBufferGranularity, uint8_t *nTransportChannels, uint8_t *nOutChannels, uint16_t *nSamplesRendered, int16_t *data ); static ivas_error IVAS_DEC_GetTcSamples( IVAS_DEC_HANDLE hIvasDec, float *pcmBuf, int16_t *nOutSamples ); static ivas_error IVAS_DEC_RendererFeedTcSamples( IVAS_DEC_HANDLE hIvasDec, const int16_t nSamplesForRendering, int16_t *nSamplesResidual, float *pcmBuf ); @@ -146,6 +165,17 @@ ivas_error IVAS_DEC_Open( } hIvasDec = *phIvasDec; hIvasDec->hVoIP = NULL; +#ifdef API_5MS + hIvasDec->apaExecBuffer = NULL; + hIvasDec->hTimeScaler = NULL; + hIvasDec->tsm_scale = 100; + hIvasDec->needNewFrame = false; + hIvasDec->nTransportChannelsOld = 0; + hIvasDec->nSamplesAvailableNext = 0; + hIvasDec->nSamplesRendered = 0; + hIvasDec->nSamplesFrame = 0; + hIvasDec->hasBeenFedFrame = false; +#endif hIvasDec->hasBeenFedFirstGoodFrame = false; hIvasDec->hasDecodedFirstGoodFrame = false; hIvasDec->isInitialized = false; @@ -241,8 +271,11 @@ static void init_decoder_config( hDecoderConfig->orientation_tracking = HEAD_ORIENT_TRK_NONE; hDecoderConfig->Opt_non_diegetic_pan = 0; hDecoderConfig->non_diegetic_pan_gain = 0; - +#ifdef API_5MS + hDecoderConfig->tsm_active = 0; +#else hDecoderConfig->voip_active = 0; +#endif hDecoderConfig->Opt_delay_comp = 0; @@ -280,6 +313,14 @@ void IVAS_DEC_Close( ( *phIvasDec )->st_ivas = NULL; } +#ifdef API_5MS + apa_exit( &( *phIvasDec )->hTimeScaler ); + + if ( ( *phIvasDec )->apaExecBuffer != NULL ) + { + free( ( *phIvasDec )->apaExecBuffer ); + } +#endif free( *phIvasDec ); *phIvasDec = NULL; phIvasDec = NULL; @@ -417,9 +458,12 @@ static IVAS_DEC_BS_FORMAT mapIvasFormat( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_Configure( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const uint32_t sampleRate, /* i : output sampling frequency */ - const IVAS_DEC_AUDIO_CONFIG outputFormat, /* i : output format */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const uint32_t sampleRate, /* i : output sampling frequency */ + const IVAS_DEC_AUDIO_CONFIG outputFormat, /* i : output format */ +#ifdef API_5MS + const int16_t tsmEnabled, /* i : enable TSM */ +#endif const int16_t customLsOutputEnabled, /* i : enable custom loudspeaker setup handle */ const int16_t hrtfReaderEnabled, /* i : enable HRTF binary file input */ const int16_t enableHeadRotation, /* i : enable head rotation for binaural output */ @@ -496,6 +540,15 @@ ivas_error IVAS_DEC_Configure( hIvasDec->st_ivas->ivas_format = MONO_FORMAT; } +#ifdef API_5MS + hDecoderConfig->tsm_active = tsmEnabled; + hIvasDec->nSamplesFrame = (uint16_t) ( hDecoderConfig->output_Fs / FRAMES_PER_SEC ); + hIvasDec->nSamplesAvailableNext = 0; + hIvasDec->nSamplesRendered = 0; + hIvasDec->tsm_scale = 100; + hIvasDec->tsm_max_scaling = 100; +#endif + return error; } @@ -510,9 +563,11 @@ ivas_error IVAS_DEC_Configure( ivas_error IVAS_DEC_EnableVoIP( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING const IVAS_DEC_VOIP_MODE voipMode, /* i : VoIP or variable speed */ const uint16_t speedFac, /* i : speed factor for variable speed */ +#endif #endif const int16_t jbmSafetyMargin, /* i : allowed delay reserve for JBM, in milliseconds */ const IVAS_DEC_INPUT_FORMAT inputFormat /* i : format of the input bitstream */ @@ -532,7 +587,11 @@ ivas_error IVAS_DEC_EnableVoIP( hDecoderConfig = hIvasDec->st_ivas->hDecoderConfig; hIvasDec->Opt_VOIP = 1; +#ifdef API_5MS + hDecoderConfig->tsm_active = 1; +#else hDecoderConfig->voip_active = 1; +#endif if ( hDecoderConfig->output_config != AUDIO_CONFIG_EXTERNAL ) { @@ -558,12 +617,15 @@ ivas_error IVAS_DEC_EnableVoIP( hIvasDec->hVoIP->lastDecodedWasActive = 0; hIvasDec->hVoIP->hCurrentDataUnit = NULL; +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING hIvasDec->hVoIP->voipMode = voipMode; hIvasDec->hVoIP->speedFac = speedFac; hIvasDec->hVoIP->needNewFrame = false; +#endif #endif hIvasDec->hVoIP->nSamplesFrame = (uint16_t) ( hDecoderConfig->output_Fs / FRAMES_PER_SEC ); +#ifndef API_5MS hIvasDec->hVoIP->nSamplesAvailableNext = 0; hIvasDec->hVoIP->rendererType = JBM_RENDERER_NONE; hIvasDec->hVoIP->hFifoOut = NULL; @@ -571,6 +633,7 @@ ivas_error IVAS_DEC_EnableVoIP( /* postpone init of the buffers until we know the real number of TCs*/ hIvasDec->hVoIP->apaExecBuffer = NULL; hIvasDec->hVoIP->nTransportChannelsOld = 0; +#endif #define WMC_TOOL_SKIP /* Bitstream conversion is not counted towards complexity and memory usage */ @@ -583,10 +646,12 @@ ivas_error IVAS_DEC_EnableVoIP( } /* initialize JBM */ +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING hIvasDec->hVoIP->hJBM = NULL; if ( hIvasDec->hVoIP->voipMode == IVAS_DEC_VOIP_MODE_VOIP ) { +#endif #endif if ( ( error = JB4_Create( &hIvasDec->hVoIP->hJBM ) != IVAS_ERR_OK ) != IVAS_ERR_OK ) { @@ -596,10 +661,13 @@ ivas_error IVAS_DEC_EnableVoIP( { return IVAS_ERR_FAILED_ALLOC; } +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING } #endif +#endif +#ifndef API_5MS /* postpone init of time scaler and output FIFO until we know the real number of TCs */ hIvasDec->hVoIP->hTimeScaler = NULL; #ifdef VARIABLE_SPEED_DECODING @@ -608,7 +676,7 @@ ivas_error IVAS_DEC_EnableVoIP( hIvasDec->hVoIP->needNewFrame = true; } #endif - +#endif return error; } @@ -652,9 +720,13 @@ ivas_error IVAS_DEC_FeedFrame_Serial( { hIvasDec->st_ivas->hDecoderConfig->ivas_total_brate = ACELP_8k00; } +#ifdef API_5MS + hIvasDec->isInitialized = true; +#endif } - +#ifndef API_5MS hIvasDec->isInitialized = true; +#endif } if ( !bfi ) /* TODO(mcjbm): Is this ok for bfi == 2 (partial frame)? Is there enough info to fully configure decoder? */ @@ -696,11 +768,18 @@ ivas_error IVAS_DEC_FeedFrame_Serial( st->use_partial_copy = 1; } +#ifdef API_5MS + hIvasDec->needNewFrame = false; + hIvasDec->hasBeenFedFrame = true; + hIvasDec->nSamplesRendered = 0; + hIvasDec->nSamplesAvailableNext = hIvasDec->nSamplesFrame; +#else #ifdef VARIABLE_SPEED_DECODING if ( hIvasDec->hVoIP != NULL && hIvasDec->hVoIP->voipMode == IVAS_DEC_VOIP_MODE_VARIABLE_SPEED ) { hIvasDec->hVoIP->needNewFrame = false; } +#endif #endif return error; @@ -712,7 +791,7 @@ ivas_error IVAS_DEC_FeedFrame_Serial( * * Main function to decode to PCM data *---------------------------------------------------------------------*/ - +#ifndef API_5MS ivas_error IVAS_DEC_GetSamples( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ @@ -767,6 +846,233 @@ ivas_error IVAS_DEC_GetSamples( return error; } +#else +ivas_error IVAS_DEC_GetSamples( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const int16_t nSamplesAsked, /* i: number of samples wanted by the caller */ + int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ + int16_t *nOutSamples, /* o : number of samples per channel written to output buffer */ + bool *needNewFrame /* indication that the decoder needs a new frame */ +#if defined SPLIT_REND_WITH_HEAD_ROT && !defined API_5MS + , + IVAS_SPLIT_REND_BITS_HANDLE hSplitRendBits /* o : bitstream output for split rendering mode*/ +#endif +) +{ + ivas_error error; + int16_t nOutSamplesElse, result, nSamplesToRender; + uint16_t nSamplesRendered, nSamplesRendered_loop, l_ts, nTimeScalerOutSamples; + uint8_t nTransportChannels, nOutChannels; + error = IVAS_ERR_OK; + nSamplesRendered = 0; + nOutChannels = 0; + + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + if ( !hIvasDec->hasBeenFedFrame && hIvasDec->nSamplesAvailableNext == 0 ) + { + /* no frame was fed, do nothing but ask for a frame */ + *needNewFrame = true; + *nOutSamples = 0; + hIvasDec->needNewFrame = true; + return error; + } + + /* check if we are still at the beginning with bad frames, put out zeroes, keep track of subframes */ + if ( !hIvasDec->isInitialized && hIvasDec->st_ivas->bfi ) + { + hIvasDec->hasBeenFedFrame = false; + set_s( pcmBuf, 0, hIvasDec->st_ivas->hDecoderConfig->nchan_out * nSamplesAsked ); + hIvasDec->nSamplesRendered += nSamplesAsked; + *nOutSamples = nSamplesAsked; + hIvasDec->nSamplesAvailableNext -= nSamplesAsked; + if ( hIvasDec->nSamplesAvailableNext == 0 ) + { + hIvasDec->needNewFrame = true; + *needNewFrame = true; + } + } + else + { + /* check if we need to run the setup function, tc decoding and feeding the renderer */ + if ( !hIvasDec->isInitialized || hIvasDec->hasBeenFedFrame ) + { + int16_t nResidualSamples, nSamplesTcsScaled; + /* setup */ + if ( ( error = IVAS_DEC_Setup( hIvasDec, &l_ts, &nTransportChannels, &nOutChannels, &nSamplesRendered_loop, pcmBuf + nSamplesRendered * nOutChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + nSamplesRendered += nSamplesRendered_loop; + if ( nTransportChannels != hIvasDec->nTransportChannelsOld ) + { + IVAS_DEC_reconfigure( hIvasDec, nTransportChannels, l_ts ); + } + /* decode TCs only */ + if ( ( error = IVAS_DEC_GetTcSamples( hIvasDec, hIvasDec->apaExecBuffer, &nOutSamplesElse ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( hIvasDec->st_ivas->hDecoderConfig->tsm_active ) + { + if ( apa_set_scale( hIvasDec->hTimeScaler, hIvasDec->tsm_scale ) != 0 ) + { + return IVAS_ERR_UNKNOWN; + } + result = apa_exec( hIvasDec->hTimeScaler, hIvasDec->apaExecBuffer, hIvasDec->nSamplesFrame * nTransportChannels, (uint16_t) hIvasDec->tsm_max_scaling, hIvasDec->apaExecBuffer, &nTimeScalerOutSamples ); + if ( result != 0 ) + { + return IVAS_ERR_UNKNOWN; + } + assert( nTimeScalerOutSamples <= APA_BUF ); + } + else + { + nTimeScalerOutSamples = hIvasDec->nSamplesFrame * nTransportChannels; + } + nSamplesTcsScaled = nTimeScalerOutSamples / nTransportChannels; + + /* render IVAS frames */ + + + if ( ( error = IVAS_DEC_RendererFeedTcSamples( hIvasDec, nSamplesTcsScaled, &nResidualSamples, hIvasDec->apaExecBuffer ) ) != IVAS_ERR_OK ) + { + return error; + } + + if ( hIvasDec->st_ivas->hDecoderConfig->tsm_active ) + { + /* feed residual samples to TSM for the next call */ + if ( apa_set_renderer_residual_samples( hIvasDec->hTimeScaler, (uint16_t) nResidualSamples ) != 0 ) + { + return IVAS_ERR_UNKNOWN; + } + } + hIvasDec->hasBeenFedFrame = false; + } + /* render IVAS frames directly to the output buffer */ + nSamplesToRender = nSamplesAsked - nSamplesRendered; + if ( ( error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesRendered_loop, &hIvasDec->nSamplesAvailableNext, pcmBuf + nSamplesRendered * nOutChannels ) ) != IVAS_ERR_OK ) + { + return error; + } + nSamplesRendered += nSamplesRendered_loop; + nSamplesToRender -= nSamplesRendered_loop; + if ( hIvasDec->nSamplesAvailableNext == 0 ) + { + *needNewFrame = true; + hIvasDec->needNewFrame = true; + } + else + { + *needNewFrame = false; + } + } + + *nOutSamples = nSamplesRendered; + + return error; +} +#endif + +#if defined API_5MS && defined SPLIT_REND_WITH_HEAD_ROT +ivas_error IVAS_DEC_GetSplitBinaural( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + IVAS_SPLIT_REND_BITS_HANDLE hSplitRendBits, /* o : bitstream output for split rendering mode*/ + int16_t *nOutSamples, /* o : number of samples per channel written to output buffer */ + bool *needNewFrame /* indication that the decoder needs a new frame */ +) +{ + Decoder_Struct *st_ivas; + AUDIO_CONFIG output_config; + int32_t output_Fs; + float output[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES][L_FRAME48k]; + int16_t output_int[BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES * L_FRAME48k]; /* TODO(sgi): Need conversion */ + int16_t numSamplesPerChannel; + int16_t i, j; + ivas_error error; + + error = IVAS_ERR_OK; + st_ivas = hIvasDec->st_ivas; + output_config = st_ivas->hDecoderConfig->output_config; + output_Fs = st_ivas->hDecoderConfig->output_Fs; + numSamplesPerChannel = output_Fs / FRAMES_PER_SEC; /* TODO(sgi): Accommodate 5ms framing */ + + if ( output_config != AUDIO_CONFIG_BINAURAL_SPLIT_CODED && output_config != AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) + { + return IVAS_ERR_WRONG_PARAMS; + } + + *nOutSamples = 0; + *needNewFrame = FALSE; + + while ( error == IVAS_ERR_OK && !*needNewFrame ) + { + int16_t nOutSamplesLocal; + + /* Decode and render */ + error = IVAS_DEC_GetSamples( + hIvasDec, + numSamplesPerChannel, + output_int, + &nOutSamplesLocal, + needNewFrame ); + if ( error != IVAS_ERR_OK || *needNewFrame ) + { + return error; + } + + *nOutSamples += nOutSamplesLocal; + + /*split rendering process calls*/ + IVAS_DEC_SPLIT_REND_WRAPPER *hSplitBinRend; + int16_t max_band; + int16_t pcm_out; + int16_t numPoses; + + hSplitBinRend = &st_ivas->splitBinRend; + + ivas_set_split_rend_setup(hSplitBinRend, &st_ivas->hRenderConfig->split_rend_config, st_ivas->hCombinedOrientationData, hSplitRendBits ); + + numPoses = hSplitBinRend->splitrend.multiBinPoseData.num_poses; + + /* [tmp] convert int back to float and change buffer layout */ + for (i = 0; i < nOutSamplesLocal; ++i) + { + for (j = 0; j < BINAURAL_CHANNELS * numPoses; ++j) + { + output[j][i] = (float) output_int[i * BINAURAL_CHANNELS * numPoses + j]; + } + } + + max_band = (int16_t) ( ( BINAURAL_MAXBANDS * output_Fs ) / 48000 ); + pcm_out = ( output_config == AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0; + + error = ivas_renderMultiBinToSplitBinaural( &hSplitBinRend->splitrend, + st_ivas->hHeadTrackData->Quaternion, + st_ivas->hRenderConfig->split_rend_config.splitRendBitRate, + st_ivas->hRenderConfig->split_rend_config.codec, + hSplitBinRend->hSplitRendBits, + hSplitBinRend->hMultiBinCldfbData->Cldfb_RealBuffer_Binaural, + hSplitBinRend->hMultiBinCldfbData->Cldfb_ImagBuffer_Binaural, + max_band, output, 1, + st_ivas->renderer_type != RENDERER_BINAURAL_FASTCONV, + pcm_out ); + if ( error != IVAS_ERR_OK ) + { + return error; + } + + free( st_ivas->splitBinRend.hMultiBinCldfbData ); + } + + return error; +} +#endif /*---------------------------------------------------------------------* @@ -1166,9 +1472,14 @@ ivas_error IVAS_DEC_GetMasaMetadata( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_FeedHeadTrackData( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - IVAS_QUATERNION *orientation, /* i : head-tracking data, listener orientation */ - IVAS_VECTOR3 *Pos /* i : listener position */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifdef API_5MS + IVAS_QUATERNION orientation, /* i : head-tracking data, listener orientation */ + IVAS_VECTOR3 Pos /* i : listener position */ +#else + IVAS_QUATERNION *orientation, /* i : head-tracking data, listener orientation */ + IVAS_VECTOR3 *Pos /* i : listener position */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , IVAS_SPLIT_REND_ROT_AXIS rot_axis @@ -1176,9 +1487,15 @@ ivas_error IVAS_DEC_FeedHeadTrackData( ) { HEAD_TRACK_DATA_HANDLE hHeadTrackData; +#ifndef API_5MS int16_t i; +#endif +#ifdef API_5MS + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) +#else if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL || orientation == NULL ) +#endif { return IVAS_ERR_UNEXPECTED_NULL_POINTER; } @@ -1191,11 +1508,21 @@ ivas_error IVAS_DEC_FeedHeadTrackData( } /* Move head-tracking data to the decoder handle */ +#ifdef API_5MS + /* check for Euler angle signaling */ + if ( orientation.w == -3.0f ) + { + Euler2Quat( deg2rad( orientation.x ), deg2rad( orientation.y ), deg2rad( orientation.z ), &orientation ); + } + + ivas_orient_trk_Process( hHeadTrackData->OrientationTracker, orientation, FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES, &hHeadTrackData->Quaternion ); + hHeadTrackData->Pos.x = Pos.x; + hHeadTrackData->Pos.y = Pos.y; + hHeadTrackData->Pos.z = Pos.z; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { /* check for Euler angle signaling */ -#ifdef SPLIT_REND_WITH_HEAD_ROT -#endif { if ( orientation[i].w == -3.0f ) { @@ -1207,9 +1534,12 @@ ivas_error IVAS_DEC_FeedHeadTrackData( hHeadTrackData->Pos[i].y = Pos[i].y; hHeadTrackData->Pos[i].z = Pos[i].z; } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT +#ifndef API_5MS hHeadTrackData->num_quaternions = 0; +#endif #else hIvasDec->st_ivas->hHeadTrackData->num_quaternions = 0; #endif @@ -1281,18 +1611,32 @@ ivas_error IVAS_DEC_FeedRefVectorData( *---------------------------------------------------------------------*/ ivas_error IVAS_DEC_FeedExternalOrientationData( - IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifdef API_5MS + IVAS_QUATERNION orientation, /* i : external orientation data */ + int8_t enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#else IVAS_QUATERNION *orientation, /* i : external orientation data */ int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#endif ) { EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData; +#ifndef API_5MS int16_t i; +#endif +#ifdef API_5MS + if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL ) +#else if ( hIvasDec == NULL || hIvasDec->st_ivas == NULL || orientation == NULL ) +#endif { return IVAS_ERR_UNEXPECTED_NULL_POINTER; } @@ -1305,6 +1649,14 @@ ivas_error IVAS_DEC_FeedExternalOrientationData( } /* Move external orientation data to the decoder handle (invert orientations) */ +#ifdef API_5MS + QuaternionInverse( orientation, &hExternalOrientationData->Quaternion ); + + hExternalOrientationData->enableHeadRotation = enableHeadRotation; + hExternalOrientationData->enableExternalOrientation = enableExternalOrientation; + hExternalOrientationData->enableRotationInterpolation = enableRotationInterpolation; + hExternalOrientationData->numFramesToTargetOrientation = numFramesToTargetOrientation; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { QuaternionInverse( orientation[i], &hExternalOrientationData->Quaternions[i] ); @@ -1314,6 +1666,7 @@ ivas_error IVAS_DEC_FeedExternalOrientationData( hExternalOrientationData->enableRotationInterpolation[i] = enableRotationInterpolation[i]; hExternalOrientationData->numFramesToTargetOrientation[i] = numFramesToTargetOrientation[i]; } +#endif return IVAS_ERR_OK; } @@ -1808,8 +2161,7 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( return IVAS_ERR_OK; } -#ifdef VARIABLE_SPEED_DECODING -#ifdef DEBUGGING +#if defined( VARIABLE_SPEED_DECODING ) || defined( API_5MS ) /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_SetScale( ) * @@ -1818,20 +2170,208 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( ivas_error IVAS_DEC_VoIP_SetScale( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - const int16_t scale /* i : TSM scale to set */ +#ifdef API_5MS + const int16_t maxScaling, +#endif + const int16_t scale /* i : TSM scale to set */ ) { ivas_error error; error = IVAS_ERR_OK; +#ifdef API_5MS + if ( hIvasDec->st_ivas->hDecoderConfig->tsm_active == false ) + { + return IVAS_ERR_TSM_NOT_ENABLED; + } + else + { + hIvasDec->tsm_scale = scale; + hIvasDec->tsm_max_scaling = maxScaling; + } +#else hIvasDec->hVoIP->speedFac = scale; +#endif return error; } #endif + + +#ifdef API_5MS +/*---------------------------------------------------------------------* + * IVAS_DEC_VoIP_GetSamples( ) + * + * Main function to decode one frame in VoIP + *---------------------------------------------------------------------*/ + +ivas_error IVAS_DEC_VoIP_GetSamples( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + uint16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ + int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ + const uint32_t systemTimestamp_ms /* i : current system timestamp */ +#ifdef SUPPORT_JBM_TRACEFILE + , + JbmTraceFileWriterFn jbmWriterFn, + void *jbmWriter #endif +) +{ + Decoder_Struct *st_ivas; + DECODER_CONFIG_HANDLE hDecoderConfig; + IVAS_DEC_VOIP *hVoIP; + uint32_t extBufferedTime_ms, scale, maxScaling; + JB4_DATAUNIT_HANDLE dataUnit; + uint16_t extBufferedSamples; + int16_t timeScalingDone; + int16_t result; + ivas_error error; + int16_t nSamplesRendered; + uint8_t nOutChannels; + + error = IVAS_ERR_OK; + + st_ivas = hIvasDec->st_ivas; + hDecoderConfig = st_ivas->hDecoderConfig; + hVoIP = hIvasDec->hVoIP; + timeScalingDone = 0; + + nOutChannels = (uint8_t) st_ivas->hDecoderConfig->nchan_out; + nSamplesRendered = 0; + + if ( nSamplesPerChannel == 0 ) + { + return IVAS_ERR_WRONG_PARAMS; + } + + /* make sure that the FIFO after decoder/scaler contains at least one sound card frame (i.e. 20ms) */ + while ( nSamplesRendered < nSamplesPerChannel ) + { + if ( hIvasDec->nSamplesAvailableNext == 0 ) + { + int16_t nSamplesBuffered; + nSamplesBuffered = 0; + if ( hIvasDec->hasBeenFedFirstGoodFrame ) + { + IVAS_DEC_GetBufferedNumberOfSamples( hIvasDec, &nSamplesBuffered ); + } + extBufferedSamples = nSamplesRendered + nSamplesBuffered; + + extBufferedTime_ms = extBufferedSamples * 1000 / hDecoderConfig->output_Fs; + + dataUnit = NULL; + + + /* pop one access unit from the jitter buffer */ + result = JB4_PopDataUnit( hVoIP->hJBM, systemTimestamp_ms, extBufferedTime_ms, &dataUnit, &scale, &maxScaling ); + if ( result != 0 ) + { + return IVAS_ERR_UNKNOWN; + } + + + maxScaling = maxScaling * hDecoderConfig->output_Fs / 1000; + /* avoid time scaling multiple times in one sound card slot */ + if ( scale != 100U ) + { + if ( timeScalingDone ) + { + scale = 100; + } + else + { + timeScalingDone = 1; + } + } + + /* limit scale to range supported by time scaler */ + if ( scale < APA_MIN_SCALE ) + { + scale = APA_MIN_SCALE; + } + else if ( scale > APA_MAX_SCALE ) + { + scale = APA_MAX_SCALE; + } + + IVAS_DEC_VoIP_SetScale( hIvasDec, (int16_t) maxScaling, (int16_t) scale ); + + /* copy bitstream into decoder state */ + if ( dataUnit ) + { + hIvasDec->hVoIP->hCurrentDataUnit = dataUnit; + + bsCompactToSerial( dataUnit->data, hIvasDec->hVoIP->bs_conversion_buf, dataUnit->dataSize ); + IVAS_DEC_FeedFrame_Serial( hIvasDec, hIvasDec->hVoIP->bs_conversion_buf, dataUnit->dataSize, 0 ); + } + else if ( hIvasDec->hasDecodedFirstGoodFrame ) + { + /* Decoder has been initialized with first good frame - do PLC */ + IVAS_DEC_FeedFrame_Serial( hIvasDec, hIvasDec->hVoIP->bs_conversion_buf, 0, 1 ); + } + +#ifdef SUPPORT_JBM_TRACEFILE + /* jbmWriterFn and jbmWriter may be NULL if tracefile writing was not requested on CLI */ + if ( jbmWriterFn != NULL && jbmWriter != NULL ) + { + /* write JBM trace data entry */ + store_JbmData( hVoIP, dataUnit, systemTimestamp_ms, extBufferedSamples, hDecoderConfig->output_Fs ); + if ( ( jbmWriterFn( &hVoIP->JbmTraceData, jbmWriter ) ) != IVAS_ERR_OK ) + { + fprintf( stderr, "\nError writing JBM Trace data to file\n" ); + return IVAS_ERR_UNKNOWN; + } + } +#endif + if ( dataUnit ) + { + if ( dataUnit->partial_frame != 0 ) + { + hVoIP->lastDecodedWasActive = 1; + } + else + { + hVoIP->lastDecodedWasActive = !dataUnit->silenceIndicator; + } + /* data unit memory is no longer used */ + JB4_FreeDataUnit( hVoIP->hJBM, dataUnit ); + } + if ( !hIvasDec->hasBeenFedFirstGoodFrame ) + { + hIvasDec->nSamplesAvailableNext = hIvasDec->nSamplesFrame; + hIvasDec->nSamplesRendered = 0; + } + } + /* decode */ + if ( !hIvasDec->hasBeenFedFirstGoodFrame ) + { + /* codec mode to use not known yet - simply output silence */ + /* directly set output zero */ + int16_t nSamplesToZero = min( nSamplesPerChannel, hIvasDec->nSamplesAvailableNext ); + set_s( pcmBuf + nSamplesRendered * nOutChannels, 0, nSamplesToZero * nOutChannels ); + nSamplesRendered += nSamplesToZero; + hIvasDec->nSamplesRendered += nSamplesToZero; + hIvasDec->nSamplesAvailableNext -= nSamplesToZero; + } + else + { + int16_t nSamplesToRender, nSamplesRendered_loop; + bool tmp; + nSamplesToRender = nSamplesPerChannel - nSamplesRendered; + + /* render IVAS frames directly to the output buffer */ + if ( ( error = IVAS_DEC_GetSamples( hIvasDec, nSamplesToRender, pcmBuf + nSamplesRendered * nOutChannels, &nSamplesRendered_loop, &tmp ) ) != IVAS_ERR_OK ) + { + return error; + } + nSamplesRendered += nSamplesRendered_loop; + } + } + return error; +} +#else /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_GetSamples( ) * @@ -2037,7 +2577,7 @@ ivas_error IVAS_DEC_VoIP_GetSamples( nSamplesRendered += nSamplesRendered_loop; if ( nTransportChannels != hVoIP->nTransportChannelsOld ) { - IVAS_DEC_VoIP_reconfigure( hIvasDec, nTransportChannels, l_ts ); + IVAS_DEC_reconfigure( hIvasDec, nTransportChannels, l_ts ); } /* decode TCs only */ @@ -2217,6 +2757,7 @@ ivas_error IVAS_DEC_VoIP_GetSamples( return error; } +#endif /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_Flush( ) @@ -2224,25 +2765,36 @@ ivas_error IVAS_DEC_VoIP_GetSamples( * Function to flush remaining audio in VoIP *---------------------------------------------------------------------*/ -ivas_error IVAS_DEC_VoIP_Flush( +ivas_error IVAS_DEC_Flush( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ const int16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ - uint16_t *nSamplesAvailableNext, /* o : number of samples still available */ - int16_t *nSamplesFlushed /* o : number of samples flushed */ +#ifndef API_5MS + uint16_t *nSamplesAvailableNext, /* o : number of samples still available */ +#endif + int16_t *nSamplesFlushed /* o : number of samples flushed */ ) { ivas_error error; +#ifndef API_5MS IVAS_DEC_VOIP *hVoIP; int16_t rendererPcmBuf[( MAX_OUTPUT_CHANNELS * L_FRAME_MAX * APA_MAX_SCALE ) / 100]; +#endif uint16_t nSamplesToRender; uint16_t nSamplesFlushedLocal; error = IVAS_ERR_OK; +#ifndef API_5MS hVoIP = hIvasDec->hVoIP; +#endif +#ifdef API_5MS + *nSamplesFlushed = min( nSamplesPerChannel, hIvasDec->nSamplesAvailableNext ); +#else *nSamplesFlushed = min( nSamplesPerChannel, hVoIP->nSamplesAvailableNext ); +#endif +#ifndef API_5MS if ( hVoIP->rendererType == JBM_RENDERER_NONE ) { /* fetch a user-specified number of samples from FIFO */ @@ -2255,6 +2807,7 @@ ivas_error IVAS_DEC_VoIP_Flush( } else { + nSamplesToRender = (uint16_t) *nSamplesFlushed; /* render IVAS frames */ if ( ( error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesFlushedLocal, &hVoIP->nSamplesAvailableNext, rendererPcmBuf ) ) != IVAS_ERR_OK ) @@ -2275,7 +2828,15 @@ ivas_error IVAS_DEC_VoIP_Flush( *nSamplesAvailableNext = hVoIP->nSamplesAvailableNext; *nSamplesFlushed = (int16_t) nSamplesFlushedLocal; } +#else + nSamplesToRender = (uint16_t) *nSamplesFlushed; + /* render IVAS frames */ + if ( ( error = IVAS_DEC_GetRenderedSamples( hIvasDec, nSamplesToRender, &nSamplesFlushedLocal, &hIvasDec->nSamplesAvailableNext, pcmBuf ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif return error; } @@ -2290,7 +2851,11 @@ bool IVAS_DEC_VoIP_IsEmpty( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ const int16_t nSamplesAsked ) { +#ifdef API_5MS + return ( ( JB4_bufferedDataUnits( hIvasDec->hVoIP->hJBM ) == 0 ) && ( hIvasDec->nSamplesAvailableNext < nSamplesAsked ) ); +#else return ( ( JB4_bufferedDataUnits( hIvasDec->hVoIP->hJBM ) == 0 ) && ( hIvasDec->hVoIP->nSamplesAvailableNext < nSamplesAsked ) ); +#endif } @@ -2329,6 +2894,7 @@ static void IVAS_DEC_Close_VoIP( { JB4_Destroy( &hVoIP->hJBM ); +#ifndef API_5MS apa_exit( &hVoIP->hTimeScaler ); pcmdsp_fifo_destroy( &hVoIP->hFifoOut ); @@ -2337,7 +2903,7 @@ static void IVAS_DEC_Close_VoIP( { free( hVoIP->apaExecBuffer ); } - +#endif if ( hVoIP->bs_conversion_buf != NULL ) { #define WMC_TOOL_SKIP @@ -2676,15 +3242,23 @@ static ivas_error printConfigInfo_dec( } } +#ifdef API_5MS + /*-----------------------------------------------------------------* + * Print VoIP mode info + *-----------------------------------------------------------------*/ + if ( st_ivas->hDecoderConfig->tsm_active ) + { + fprintf( stdout, "TSM mode: ON\n" ); + } +#else /*-----------------------------------------------------------------* * Print VoIP mode info *-----------------------------------------------------------------*/ - if ( st_ivas->hDecoderConfig->voip_active ) { fprintf( stdout, "VoIP mode: ON\n" ); } - +#endif return IVAS_ERR_OK; } @@ -2858,7 +3432,15 @@ static ivas_error evs_dec_main( v_multc( output[0], mixer_left, output[0], nOutSamples ); } - if ( floatBuf != NULL ) + +#ifdef API_5MS + if ( !st_ivas->hDecoderConfig->tsm_active ) + { + ivas_jbm_dec_copy_tc_no_tsm( st_ivas, p_output, nOutSamples ); + } + else +#endif + if ( floatBuf != NULL ) { /* BE workaround */ int16_t pcm_buf_local[L_FRAME48k * MAX_OUTPUT_CHANNELS_IN_DIEGETIC_PAN]; @@ -3084,6 +3666,7 @@ static int16_t IVAS_DEC_VoIP_GetRenderGranularity( } +#ifndef API_5MS /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_GetRendererConfig() * @@ -3107,7 +3690,7 @@ static JBM_RENDERER_TYPE IVAS_DEC_VoIP_GetRendererConfig( return rendererType; } - +#endif /*---------------------------------------------------------------------* * IVAS_DEC_VoIP_reconfigure() @@ -3115,64 +3698,106 @@ static JBM_RENDERER_TYPE IVAS_DEC_VoIP_GetRendererConfig( * *---------------------------------------------------------------------*/ -ivas_error IVAS_DEC_VoIP_reconfigure( +ivas_error IVAS_DEC_reconfigure( IVAS_DEC_HANDLE hIvasDec, const uint16_t nTransportChannels, const uint16_t l_ts ) { +#ifndef API_5MS IVAS_DEC_VOIP *hVoIP; +#endif +#ifdef API_5MS + int16_t apa_buffer_size; +#endif + ivas_error error; +#ifndef API_5MS hVoIP = hIvasDec->hVoIP; +#endif +#ifdef API_5MS + apa_buffer_size = hIvasDec->nSamplesFrame; +#endif +#ifdef API_5MS + if ( hIvasDec->apaExecBuffer == NULL ) +#else if ( hIvasDec->hVoIP->hTimeScaler == NULL ) +#endif { - +#ifndef API_5MS uint16_t wss, css; float startQuality; +#endif DECODER_CONFIG_HANDLE hDecoderConfig; +#ifdef API_5MS + if ( hIvasDec->st_ivas->hDecoderConfig->tsm_active ) + { + uint16_t wss, css; + float startQuality; + + startQuality = 1.0f; + apa_buffer_size = APA_BUF_PER_CHANNEL; +#else #ifdef VARIABLE_SPEED_DECODING startQuality = hVoIP->voipMode == IVAS_DEC_VOIP_MODE_VARIABLE_SPEED ? -2.0f : 1.0f; #else startQuality = 1.0f; +#endif #endif - /* get current renderer type*/ - hVoIP->rendererType = IVAS_DEC_VoIP_GetRendererConfig( hIvasDec ); - hDecoderConfig = hIvasDec->st_ivas->hDecoderConfig; - if ( hDecoderConfig->output_Fs == 8000 ) - { - wss = 1; - css = 1; - } - else if ( hDecoderConfig->output_Fs == 16000 ) - { - wss = 2; - css = 1; - } - else if ( hDecoderConfig->output_Fs == 32000 ) - { - wss = 4; - css = 2; - } - else if ( hDecoderConfig->output_Fs == 48000 ) - { - wss = 6; - css = 3; - } - else - { - return IVAS_ERR_INIT_ERROR; - } + /* get current renderer type*/ +#ifndef API_5MS + hVoIP->rendererType = IVAS_DEC_VoIP_GetRendererConfig( hIvasDec ); +#endif + hDecoderConfig = hIvasDec->st_ivas->hDecoderConfig; - if ( ( hIvasDec->hVoIP->apaExecBuffer = malloc( sizeof( float ) * APA_BUF_PER_CHANNEL * nTransportChannels ) ) == NULL ) - { - return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); - } - set_zero( hIvasDec->hVoIP->apaExecBuffer, APA_BUF_PER_CHANNEL * nTransportChannels ); + if ( hDecoderConfig->output_Fs == 8000 ) + { + wss = 1; + css = 1; + } + else if ( hDecoderConfig->output_Fs == 16000 ) + { + wss = 2; + css = 1; + } + else if ( hDecoderConfig->output_Fs == 32000 ) + { + wss = 4; + css = 2; + } + else if ( hDecoderConfig->output_Fs == 48000 ) + { + wss = 6; + css = 3; + } + else + { + return IVAS_ERR_INIT_ERROR; + } +#ifndef API_5MS + if ( ( hIvasDec->hVoIP->apaExecBuffer = malloc( sizeof( float ) * APA_BUF_PER_CHANNEL * nTransportChannels ) ) == NULL ) + + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); + } + set_zero( hIvasDec->hVoIP->apaExecBuffer, APA_BUF_PER_CHANNEL * nTransportChannels ); +#endif +#ifdef API_5MS + if ( apa_init( &hIvasDec->hTimeScaler, + nTransportChannels ) != IVAS_ERR_OK || + apa_set_rate( hIvasDec->hTimeScaler, hDecoderConfig->output_Fs ) != 0 || + apa_set_complexity_options( hIvasDec->hTimeScaler, wss, css ) != 0 || + apa_set_quality( hIvasDec->hTimeScaler, startQuality, 4, 4 ) != 0 || + apa_set_renderer_granularity( hIvasDec->hTimeScaler, l_ts ) != 0 ) + { + return IVAS_ERR_INIT_ERROR; + } +#else if ( apa_init( &hIvasDec->hVoIP->hTimeScaler, nTransportChannels ) != IVAS_ERR_OK || apa_set_rate( hIvasDec->hVoIP->hTimeScaler, hDecoderConfig->output_Fs ) != 0 || @@ -3182,51 +3807,99 @@ ivas_error IVAS_DEC_VoIP_reconfigure( { return IVAS_ERR_INIT_ERROR; } +#endif - if ( hVoIP->hFifoOut == NULL && hVoIP->rendererType == JBM_RENDERER_NONE ) - { - /* we still need the FIFO out buffer */ - if ( pcmdsp_fifo_create( &hIvasDec->hVoIP->hFifoOut ) != 0 || - pcmdsp_fifo_init( hIvasDec->hVoIP->hFifoOut, (uint16_t) ( hDecoderConfig->output_Fs * 4 / FRAMES_PER_SEC ) /* 4 frames */, hDecoderConfig->nchan_out, sizeof( int16_t ) ) != 0 ) +#ifndef API_5MS + if ( hVoIP->hFifoOut == NULL && hVoIP->rendererType == JBM_RENDERER_NONE ) { - return IVAS_ERR_INIT_ERROR; + /* we still need the FIFO out buffer */ + if ( pcmdsp_fifo_create( &hIvasDec->hVoIP->hFifoOut ) != 0 || + pcmdsp_fifo_init( hIvasDec->hVoIP->hFifoOut, (uint16_t) ( hDecoderConfig->output_Fs * 4 / FRAMES_PER_SEC ) /* 4 frames */, hDecoderConfig->nchan_out, sizeof( int16_t ) ) != 0 ) + { + return IVAS_ERR_INIT_ERROR; + } } - } #ifdef VARIABLE_SPEED_DECODING - else if ( hIvasDec->hVoIP->voipMode == IVAS_DEC_VOIP_MODE_VARIABLE_SPEED ) - { - if ( pcmdsp_fifo_create( &hIvasDec->hVoIP->hFifoOut ) != 0 || - pcmdsp_fifo_init( hIvasDec->hVoIP->hFifoOut, (uint16_t) ( hDecoderConfig->output_Fs * 4 / FRAMES_PER_SEC ) /* 4 frames */, hDecoderConfig->nchan_out, sizeof( int16_t ) ) != 0 ) + else if ( hIvasDec->hVoIP->voipMode == IVAS_DEC_VOIP_MODE_VARIABLE_SPEED ) { - return IVAS_ERR_INIT_ERROR; + if ( pcmdsp_fifo_create( &hIvasDec->hVoIP->hFifoOut ) != 0 || + pcmdsp_fifo_init( hIvasDec->hVoIP->hFifoOut, (uint16_t) ( hDecoderConfig->output_Fs * 4 / FRAMES_PER_SEC ) /* 4 frames */, hDecoderConfig->nchan_out, sizeof( int16_t ) ) != 0 ) + { + return IVAS_ERR_INIT_ERROR; + } } - } +#endif #endif - if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) - { + if ( hIvasDec->mode == IVAS_DEC_MODE_EVS ) + { +#ifdef API_5MS + if ( apa_set_evs_compat_mode( hIvasDec->hTimeScaler, true ) != 0 ) +#else if ( apa_set_evs_compat_mode( hIvasDec->hVoIP->hTimeScaler, true ) != 0 ) +#endif + { + return IVAS_ERR_INIT_ERROR; + } + } +#ifdef API_5MS + if ( ( hIvasDec->apaExecBuffer = malloc( sizeof( float ) * apa_buffer_size * nTransportChannels ) ) == NULL ) + { - return IVAS_ERR_INIT_ERROR; + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); } + + set_zero( hIvasDec->apaExecBuffer, apa_buffer_size * nTransportChannels ); + } +#endif +#ifndef API_5MS + if ( ( hVoIP->apaExecBuffer = malloc( sizeof( float ) * APA_BUF_PER_CHANNEL * nTransportChannels ) ) == NULL ) + + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); } + + set_zero( hVoIP->apaExecBuffer, APA_BUF_PER_CHANNEL * nTransportChannels ); +#endif } else { - if ( apa_reconfigure( hVoIP->hTimeScaler, nTransportChannels, l_ts ) != 0 ) +#ifdef API_5MS + if ( hIvasDec->st_ivas->hDecoderConfig->tsm_active ) { - return IVAS_ERR_INIT_ERROR; + if ( apa_reconfigure( hIvasDec->hTimeScaler, nTransportChannels, l_ts ) != 0 ) +#else + if ( apa_reconfigure( hVoIP->hTimeScaler, nTransportChannels, l_ts ) != 0 ) +#endif + { + return IVAS_ERR_INIT_ERROR; + } +#ifdef API_5MS + apa_buffer_size = APA_BUF_PER_CHANNEL; + free( hIvasDec->apaExecBuffer ); + if ( ( hIvasDec->apaExecBuffer = malloc( sizeof( float ) * apa_buffer_size * nTransportChannels ) ) == NULL ) + { + return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); + } + set_zero( hIvasDec->apaExecBuffer, apa_buffer_size * nTransportChannels ); } - +#endif /* realloc apa_exe_buffer */ +#ifndef API_5MS free( hIvasDec->hVoIP->apaExecBuffer ); if ( ( hIvasDec->hVoIP->apaExecBuffer = malloc( sizeof( float ) * APA_BUF_PER_CHANNEL * nTransportChannels ) ) == NULL ) { return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Could not allocate VoIP handle" ); } set_zero( hIvasDec->hVoIP->apaExecBuffer, APA_BUF_PER_CHANNEL * nTransportChannels ); +#endif } + +#ifdef API_5MS + hIvasDec->nTransportChannelsOld = nTransportChannels; +#else hIvasDec->hVoIP->nTransportChannelsOld = (uint8_t) nTransportChannels; +#endif error = IVAS_ERR_OK; diff --git a/lib_dec/lib_dec.h b/lib_dec/lib_dec.h index 9edc1a130c0bb520db9e529fd779361a263c5940..a897c1e0c672b0bc70e40744dc3cb0d0ea5b48c0 100644 --- a/lib_dec/lib_dec.h +++ b/lib_dec/lib_dec.h @@ -88,7 +88,7 @@ typedef enum _IVAS_DEC_COMPLEXITY_LEVEL IVAS_DEC_COMPLEXITY_LEVEL_THREE = 3 } IVAS_DEC_COMPLEXITY_LEVEL; - +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING typedef enum { @@ -96,6 +96,7 @@ typedef enum IVAS_DEC_VOIP_MODE_VARIABLE_SPEED = 1 } IVAS_DEC_VOIP_MODE; #endif +#endif #ifdef DEBUGGING typedef enum _IVAS_DEC_FORCED_REND_MODE @@ -145,11 +146,14 @@ ivas_error IVAS_DEC_Configure( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ const uint32_t sampleRate, /* i : output sampling frequency */ const IVAS_DEC_AUDIO_CONFIG outputFormat, /* i : output format */ +#ifdef API_5MS + const int16_t tsmEnabled, /* i : enable TSM */ +#endif const int16_t customLsOutputEnabled, /* i : enable custom loudspeaker setup handle */ const int16_t hrtfReaderEnabled, /* i : enable HRTF binary file input */ const int16_t enableHeadRotation, /* i : enable head rotation for binaural output */ const int16_t enableExternalOrientation, /* i : enable external orientations */ - const HEAD_ORIENT_TRK_T orientation_tracking, /* i : head orientation tracking type */ + const HEAD_ORIENT_TRK_T orientation_tracking, /* i : head orientation tracking type */ const int16_t renderConfigEnabled, /* i : enable Renderer config. file for binaural output */ const int16_t Opt_non_diegetic_pan, /* i : diegetic or not */ const float non_diegetic_pan_gain, /* i : non diegetic panning gain */ @@ -173,15 +177,32 @@ ivas_error IVAS_DEC_FeedFrame_Serial( /*! r: decoder error code */ ivas_error IVAS_DEC_GetSamples( +#ifdef API_5MS + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const int16_t nSamplesAsked, /* i: number of samples wanted by the caller */ + int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ + int16_t *nOutSamples, /* o : number of samples per channel written to output buffer */ + bool *needNewFrame /* indication that the decoder needs a new frame */ +#else IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ int16_t *nOutSamples /* o : number of samples per channel written to output buffer */ -#ifdef SPLIT_REND_WITH_HEAD_ROT +#endif +#if defined SPLIT_REND_WITH_HEAD_ROT && !defined API_5MS , IVAS_SPLIT_REND_BITS_HANDLE hSplitRendBits /* o : bitstream output for split rendering mode*/ #endif ); +#if defined API_5MS && defined SPLIT_REND_WITH_HEAD_ROT +ivas_error IVAS_DEC_GetSplitBinaural( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + IVAS_SPLIT_REND_BITS_HANDLE hSplitRendBits, /* o : bitstream output for split rendering mode*/ + int16_t *nOutSamples, /* o : number of samples per channel written to output buffer */ + bool *needNewFrame /* indication that the decoder needs a new frame */ +); +#endif + /*! r: error code */ ivas_error IVAS_DEC_GetObjectMetadata( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ @@ -205,8 +226,13 @@ ivas_error IVAS_DEC_GetMasaMetadata( /*! r: error code */ ivas_error IVAS_DEC_FeedHeadTrackData( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - IVAS_QUATERNION *orientation, /* i : head-tracking data */ - IVAS_VECTOR3 *Pos /* i : listener position */ +#ifdef API_5MS + IVAS_QUATERNION orientation, /* i : head-tracking data, listener orientation */ + IVAS_VECTOR3 Pos /* i : listener position */ +#else + IVAS_QUATERNION *orientation, /* i : head-tracking data, listener orientation */ + IVAS_VECTOR3 *Pos /* i : listener position */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , IVAS_SPLIT_REND_ROT_AXIS rot_axis /*i : external control for rotation axis for split rendering*/ @@ -228,11 +254,19 @@ ivas_error IVAS_DEC_FeedRefVectorData( /*! r: error code */ ivas_error IVAS_DEC_FeedExternalOrientationData( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ - IVAS_QUATERNION *orientation, /* i : external orientation data */ - int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ - int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ - int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ - int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#ifdef API_5MS + IVAS_QUATERNION orientation, /* i : external orientation data */ + int8_t enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#else + IVAS_QUATERNION *orientation, /* i : external orientation data */ + int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#endif ); /*! r: error code */ @@ -246,6 +280,13 @@ ivas_error IVAS_DEC_VoIP_FeedFrame( const bool qBit /* i : Q bit for AMR-WB IO */ ); +#ifdef API_5MS +ivas_error IVAS_DEC_VoIP_SetScale( + IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ + const int16_t maxScaling, /* i : maximum allowed TSM scale */ + const int16_t scale /* i : TSM scale to set */ +); +#else #ifdef VARIABLE_SPEED_DECODING #ifdef DEBUGGING /*! r: error code */ @@ -255,25 +296,31 @@ ivas_error IVAS_DEC_VoIP_SetScale( ); #endif #endif +#endif /*! r: error code */ ivas_error IVAS_DEC_VoIP_GetSamples( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ uint16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ - const uint32_t systemTimestamp_ms, /* i : current system timestamp */ + const uint32_t systemTimestamp_ms /* i : current system timestamp */ +#ifndef API_5MS + , uint16_t *sampleAvailableNext /* o : samples available for the next call */ +#endif #ifdef SUPPORT_JBM_TRACEFILE , JbmTraceFileWriterFn jbmWriterFn, void* jbmWriter #endif ); -ivas_error IVAS_DEC_VoIP_Flush( +ivas_error IVAS_DEC_Flush( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ const int16_t nSamplesPerChannel, /* i : number of samples per channel requested to be written to output buffer */ int16_t *pcmBuf, /* i/o: buffer for decoded PCM output. The memory must already be allocated and be able to hold the expected number of output samples, based on frame size and number of output channels */ - uint16_t *nSamplesAvailableNext, /* o : number of samples still available */ +#ifndef API_5MS + uint16_t *nSamplesAvailableNext, /* o : number of samples still available */ +#endif int16_t *nSamplesFlushed /* o : number of samples flushed */ ); @@ -282,9 +329,11 @@ ivas_error IVAS_DEC_VoIP_Flush( /*! r: error code */ ivas_error IVAS_DEC_EnableVoIP( IVAS_DEC_HANDLE hIvasDec, /* i/o: IVAS decoder handle */ +#ifndef API_5MS #ifdef VARIABLE_SPEED_DECODING const IVAS_DEC_VOIP_MODE voipMode, /* i : VoIP or variable speed */ const uint16_t speedFac, /* i : speed factor for variable speed */ +#endif #endif const int16_t jbmSafetyMargin, /* i : allowed delay reserve for JBM, in milliseconds */ const IVAS_DEC_INPUT_FORMAT inputFormat /* i : format of the input bitstream */ diff --git a/lib_rend/ivas_crend.c b/lib_rend/ivas_crend.c index e33304356017dc0b89a9cbfdb1cc05dc2b83b518..6db2a8ccceed548eac0f4e029e1c37ed266d34fb 100644 --- a/lib_rend/ivas_crend.c +++ b/lib_rend/ivas_crend.c @@ -1451,13 +1451,21 @@ ivas_error ivas_rend_crendProcess( EFAP_HANDLE hEFAPdata, float *output[], /* i/o: input/output audio channels */ const int32_t output_Fs +#ifdef LIB_REND_API_5MS + , + const int16_t num_subframes /* i : number of subframes to render */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , const int16_t pos_idx #endif ) { +#ifdef LIB_REND_API_5MS + int16_t i, subframe_idx, subframe_len; +#else int16_t i, subframe_idx, output_frame, subframe_len; +#endif int16_t nchan_out; float pcm_tmp[BINAURAL_CHANNELS][L_FRAME48k]; float *p_pcm_tmp[BINAURAL_CHANNELS]; @@ -1479,6 +1487,12 @@ ivas_error ivas_rend_crendProcess( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + if ( hCombinedOrientationData->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( hCombinedOrientationData->enableCombinedOrientation[subframe_idx] != 0 ) @@ -1487,6 +1501,7 @@ ivas_error ivas_rend_crendProcess( break; } } +#endif } push_wmops( "ivas_rend_crendProcess" ); @@ -1503,15 +1518,23 @@ ivas_error ivas_rend_crendProcess( return error; } +#ifdef LIB_REND_API_5MS + subframe_len = (int16_t) output_Fs / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES; +#else output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC ); subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES; +#endif for ( i = 0; i < BINAURAL_CHANNELS; i++ ) { p_pcm_tmp[i] = pcm_tmp[i]; } +#ifdef LIB_REND_API_5MS + for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ ) +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) +#endif { if ( hDecoderConfig && combinedOrientationEnabled ) { @@ -1565,7 +1588,11 @@ ivas_error ivas_rend_crendProcess( /* move to output */ for ( i = 0; i < nchan_out; i++ ) { +#ifdef LIB_REND_API_5MS + mvr2r( pcm_tmp[i], output[i], num_subframes * subframe_len ); +#else mvr2r( pcm_tmp[i], output[i], output_frame ); +#endif } pop_wmops(); @@ -1610,6 +1637,12 @@ ivas_error ivas_rend_crendProcessSubframe( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + if ( hCombinedOrientationData->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( hCombinedOrientationData->enableCombinedOrientation[subframe_idx] != 0 ) @@ -1618,6 +1651,7 @@ ivas_error ivas_rend_crendProcessSubframe( break; } } +#endif } push_wmops( "ivas_rend_crendProcessSubframe" ); @@ -1795,6 +1829,16 @@ ivas_error ivas_rend_crendProcessSplitBin( combinedOrientationDataLocal = *pCombinedOrientationDataLocal; if ( pMultiBinPoseData->poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = combinedOrientationDataLocal.Quaternion; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + combinedOrientationDataLocal.Rmat[i][j] = combinedOrientationDataLocal.Rmat[i][j]; + } + } +#else for ( sf = 1; sf < RENDERER_HEAD_POSITIONS_PER_FRAME; ++sf ) { combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0]; @@ -1806,6 +1850,7 @@ ivas_error ivas_rend_crendProcessSplitBin( } } } +#endif } /* copy LFE to tmpLfeBuffer and apply gain only once */ @@ -1825,6 +1870,18 @@ ivas_error ivas_rend_crendProcessSplitBin( for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; ++pos_idx ) { /* Update head positions */ +#ifdef API_5MS + IVAS_QUATERNION Quaternion_orig, Quaternion_abs; + Quaternion_orig = combinedOrientationDataLocal.Quaternion; + Quaternion_abs.w = -3.0f; + Quat2EulerDegree( combinedOrientationDataLocal.Quaternion, &Quaternion_abs.z, &Quaternion_abs.y, &Quaternion_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ + + Quaternion_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + Quaternion_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + Quaternion_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + combinedOrientationDataLocal.Quaternion = Quaternion_abs; + QuatToRotMat( combinedOrientationDataLocal.Quaternion, combinedOrientationDataLocal.Rmat ); +#else IVAS_QUATERNION Quaternions_orig[RENDERER_HEAD_POSITIONS_PER_FRAME], Quaternions_abs; for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { @@ -1838,6 +1895,7 @@ ivas_error ivas_rend_crendProcessSplitBin( combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs; QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] ); } +#endif /* render inplace to first two channels of tmpInputBuffer */ pCombinedOrientationDataLocal = &combinedOrientationDataLocal; @@ -1855,6 +1913,9 @@ ivas_error ivas_rend_crendProcessSplitBin( hEFAPdata, p_tmpInputBuffer, output_Fs, +#ifdef API_5MS + 4, +#endif pos_idx ) ) != IVAS_ERR_OK ) { return error; @@ -1880,10 +1941,14 @@ ivas_error ivas_rend_crendProcessSplitBin( } /* restore original headrotation data */ +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = Quaternion_orig; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i]; } +#endif } diff --git a/lib_rend/ivas_dirac_dec_binaural_functions.c b/lib_rend/ivas_dirac_dec_binaural_functions.c index 8a3f33b80b1949416653dfb99e889414c3e22b6d..695c0f955e371567502c02059e59809e6260edf4 100644 --- a/lib_rend/ivas_dirac_dec_binaural_functions.c +++ b/lib_rend/ivas_dirac_dec_binaural_functions.c @@ -277,7 +277,11 @@ ivas_error ivas_dirac_dec_init_binaural_data( st_ivas->hDiracDecBin = hDiracDecBin; /* allocate transport channels*/ +#ifdef API_5MS + if ( st_ivas->hTcBuffer == NULL ) +#else if ( st_ivas->hDecoderConfig->voip_active == 1 && st_ivas->hTcBuffer == NULL ) +#endif { int16_t nchan_to_allocate; @@ -488,6 +492,10 @@ void ivas_dirac_dec_binaural( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ +#ifdef LIB_REND_API_5MS + , + const int16_t num_subframes /* i : number of subframes to render */ +#endif ) { int16_t subframe; @@ -542,7 +550,11 @@ void ivas_dirac_dec_binaural( generate_masking_noise_lb_dirac( st->hFdCngDec->hFdCngCom, st_ivas->hTcBuffer->tc[nchan_transport], DEFAULT_JBM_CLDFB_TIMESLOTS, st->cna_dirac_flag && st->flag_cna ); } +#ifdef LIB_REND_API_5MS + for ( subframe = 0; subframe < num_subframes; subframe++ ) +#else for ( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ ) +#endif { int16_t n_samples_sf = slot_size * hSpatParamRendCom->subframe_nbslots[subframe]; @@ -736,7 +748,11 @@ static void ivas_dirac_dec_binaural_internal( { for ( j = 0; j < 3; j++ ) { +#ifdef API_5MS + Rmat[i][j] = hCombinedOrientationData->Rmat[i][j]; +#else Rmat[i][j] = hCombinedOrientationData->Rmat[subframe][i][j]; +#endif } } @@ -749,7 +765,11 @@ static void ivas_dirac_dec_binaural_internal( } ivas_dirac_dec_binaural_formulate_input_and_target_covariance_matrices( hDiracDecBin, hSpatParamRendCom, &config_data, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, Rmat, subframe, +#ifdef API_5MS + hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation > 0 ); +#else hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[subframe] > 0 ); +#endif if ( config_data.ivas_format == ISM_FORMAT ) { @@ -765,7 +785,11 @@ static void ivas_dirac_dec_binaural_internal( } ivas_dirac_dec_binaural_determine_processing_matrices( hDiracDecBin, hSpatParamRendCom, &config_data, max_band_decorr, Rmat, +#ifdef API_5MS + hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation > 0 ); +#else hCombinedOrientationData && hCombinedOrientationData->enableCombinedOrientation[subframe] > 0 ); +#endif ivas_dirac_dec_binaural_process_output( hDiracDecBin, hSpatParamRendCom, st_ivas->cldfbSynDec, output_f, Cldfb_RealBuffer_in, Cldfb_ImagBuffer_in, max_band_decorr, numInChannels, config_data.processReverb, subframe ); hDiracDecBin->hDiffuseDist = NULL; diff --git a/lib_rend/ivas_objectRenderer.c b/lib_rend/ivas_objectRenderer.c index d37f319776aa65ff1a5a8a8927982294ea0239ba..4cdca32cb03995c5e2b482eca88deda8fdb4c748 100644 --- a/lib_rend/ivas_objectRenderer.c +++ b/lib_rend/ivas_objectRenderer.c @@ -268,6 +268,10 @@ ivas_error ivas_td_binaural_renderer_unwrap( const int16_t ism_md_subframe_update, /* i : Number of subframes to delay ism metadata to sync with audio */ float *output[], /* i/o: SCE channels / Binaural synthesis */ const int16_t output_frame /* i : output frame length */ +#ifdef LIB_REND_API_5MS + , + const int16_t num_subframes /* i : number of subframes to render */ +#endif ) { int16_t subframe_length; @@ -283,7 +287,11 @@ ivas_error ivas_td_binaural_renderer_unwrap( p_reverb_signal[ch] = reverb_signal[ch]; } +#ifdef LIB_REND_API_5MS + subframe_length = output_frame / num_subframes; +#else subframe_length = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES; +#endif c_indx = 0; for ( nS = 0; nS < num_src; nS++ ) @@ -311,7 +319,11 @@ ivas_error ivas_td_binaural_renderer_unwrap( #endif } +#ifdef LIB_REND_API_5MS + for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ ) +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) +#endif { if ( subframe_idx == ism_md_subframe_update ) { @@ -319,8 +331,11 @@ ivas_error ivas_td_binaural_renderer_unwrap( TDREND_Update_object_positions( hBinRendererTd, num_src, ivas_format, hIsmMetaData ); } /* Update the listener's location/orientation */ +#ifdef API_5MS + TDREND_Update_listener_orientation( hBinRendererTd, ( enableCombinedOrientation != NULL ) ? *enableCombinedOrientation : 0, ( Quaternions != NULL ) ? Quaternions : NULL, ( Pos != NULL ) ? Pos : NULL ); +#else TDREND_Update_listener_orientation( hBinRendererTd, ( enableCombinedOrientation != NULL ) ? enableCombinedOrientation[subframe_idx] : 0, ( Quaternions != NULL ) ? &Quaternions[subframe_idx] : NULL, ( Pos != NULL ) ? &Pos[subframe_idx] : NULL ); - +#endif if ( hReverb != NULL ) { if ( ( error = ivas_reverb_process( hReverb, transport_config, 0, output, p_reverb_signal, subframe_idx ) ) != IVAS_ERR_OK ) @@ -427,7 +442,7 @@ ivas_error TDREND_GetMix( { pan_left = ( SrcSpatial_p->Pos_p[1] + 1.f ) * 0.5f; pan_right = 1.f - pan_left; -#ifdef FIX_550_FIRST_FRAME_ACCESS +#if !defined FIX_550_FIRST_FRAME_ACCESS || !defined FIX_XXX_TDOBJRENDERER_INPUT v_multc_acc( Src_p->InputFrame_p, pan_left, output_buf[0], subframe_length ); v_multc_acc( Src_p->InputFrame_p, pan_right, output_buf[1], subframe_length ); #else @@ -435,6 +450,9 @@ ivas_error TDREND_GetMix( v_multc_acc( &Src_p->InputFrame_p[subframe_idx * subframe_length], pan_right, output_buf[1], subframe_length ); #endif } +#endif +#ifdef FIX_XXX_TDOBJRENDERER_INPUT + Src_p->InputFrame_p += subframe_length; #endif } @@ -749,10 +767,21 @@ ivas_error ivas_td_binaural_renderer_ext( } if ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, +#ifdef API_5MS + ( hCombinedOrientationData != NULL ) ? &( *hCombinedOrientationData )->enableCombinedOrientation : NULL, + ( hCombinedOrientationData != NULL ) ? &( *hCombinedOrientationData )->Quaternion : NULL, + ( hCombinedOrientationData != NULL ) ? &( *hCombinedOrientationData )->listenerPos : NULL, +#else ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->enableCombinedOrientation : NULL, ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->Quaternions : NULL, ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->listenerPos : NULL, - ism_md_subframe_update_ext, p_output, output_frame ) ) != IVAS_ERR_OK ) +#endif + ism_md_subframe_update_ext, p_output, output_frame +#ifdef LIB_REND_API_5MS + , + 1 +#endif + ) ) != IVAS_ERR_OK ) { return error; } @@ -780,7 +809,11 @@ void ObjRenderIvasFrame_splitBinaural( float *p_tmpProcessing[MAX_OUTPUT_CHANNELS]; int16_t pos_idx; +#ifdef API_5MS + IVAS_QUATERNION originalHeadRot; +#else IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; BINAURAL_TD_OBJECT_RENDERER_HANDLE tmpTdRendHandle; @@ -808,10 +841,14 @@ void ObjRenderIvasFrame_splitBinaural( } /* Save current head positions */ +#ifdef API_5MS + originalHeadRot = st_ivas->hCombinedOrientationData->Quaternion; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { originalHeadRot[i] = st_ivas->hCombinedOrientationData->Quaternions[i]; } +#endif /* Copy input audio to a processing buffer. Cannot render in-place because binaurally rendered * audio would overwrite original material, which is still needed for rendering next head pose. */ @@ -825,6 +862,26 @@ void ObjRenderIvasFrame_splitBinaural( /* Update head positions */ if ( pos_idx != 0 ) { +#ifdef API_5MS + if ( originalHeadRot.w == -3.0f ) + { + st_ivas->hCombinedOrientationData->Quaternion.w = -3.0f; + st_ivas->hCombinedOrientationData->Quaternion.x = originalHeadRot.x + pMultiBinPoseData->relative_head_poses[pos_idx][0]; + st_ivas->hCombinedOrientationData->Quaternion.y = originalHeadRot.y + pMultiBinPoseData->relative_head_poses[pos_idx][1]; + st_ivas->hCombinedOrientationData->Quaternion.z = originalHeadRot.z + pMultiBinPoseData->relative_head_poses[pos_idx][2]; + } + else + { + st_ivas->hCombinedOrientationData->Quaternion.w = -3.0f; + Quat2EulerDegree( originalHeadRot, /* TODO tmu : fix bug with ordering*/ + &st_ivas->hCombinedOrientationData->Quaternion.z, + &st_ivas->hCombinedOrientationData->Quaternion.y, + &st_ivas->hCombinedOrientationData->Quaternion.x ); + st_ivas->hCombinedOrientationData->Quaternion.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + st_ivas->hCombinedOrientationData->Quaternion.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + st_ivas->hCombinedOrientationData->Quaternion.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { if ( originalHeadRot[i].w == -3.0f ) @@ -846,6 +903,7 @@ void ObjRenderIvasFrame_splitBinaural( st_ivas->hCombinedOrientationData->Quaternions[i].z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; } } +#endif } /* Handle the 1 ISM case where there is only one channel in the input buffer */ for ( i = 0; i < max( st_ivas->nchan_transport, BINAURAL_CHANNELS ); ++i ) @@ -887,10 +945,14 @@ void ObjRenderIvasFrame_splitBinaural( } /* Restore original head rotation */ +#ifdef API_5MS + st_ivas->hCombinedOrientationData->Quaternion = originalHeadRot; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { st_ivas->hCombinedOrientationData->Quaternions[i] = originalHeadRot[i]; } +#endif pop_wmops(); } diff --git a/lib_rend/ivas_objectRenderer_hrFilt.c b/lib_rend/ivas_objectRenderer_hrFilt.c index 8fb081da222f217a1e4d8fdd4853d46685757e78..d3578c379a0742985ad7e0ebcd494fc994c1ac21 100644 --- a/lib_rend/ivas_objectRenderer_hrFilt.c +++ b/lib_rend/ivas_objectRenderer_hrFilt.c @@ -79,7 +79,7 @@ ivas_error TDREND_REND_RenderSourceHRFilt( v_add( LeftOutputFrame, output_buf[0], output_buf[0], subframe_length ); v_add( RightOutputFrame, output_buf[1], output_buf[1], subframe_length ); -#ifndef FIX_550_FIRST_FRAME_ACCESS +#if !defined FIX_550_FIRST_FRAME_ACCESS || !defined FIX_XXX_TDOBJRENDERER_INPUT Src_p->InputFrame_p += subframe_length; /* Increment input pointer */ #endif diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 7b345e6910357442aeaf7bbc4e885e2a480193ae..941eeff6c26c73792c779aedea18f881a58ebdda 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -164,6 +164,9 @@ void ivas_dirac_dec_binaural( COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : combined orientation handle */ float output_f[][L_FRAME48k], /* i/o: synthesized core-coder transport channels/DirAC output */ const int16_t nchan_transport /* i : number of transport channels */ +#ifdef LIB_REND_API_5MS + ,const int16_t num_subframes /* i : number of subframes to render */ +#endif ); void ivas_dirac_dec_binaural_render( @@ -570,6 +573,9 @@ ivas_error ivas_td_binaural_renderer_unwrap( const int16_t ism_md_subframe_update, float *output[], /* i/o: SCE channels / Binaural synthesis */ const int16_t output_frame /* i : output frame length */ +#ifdef LIB_REND_API_5MS + ,const int16_t num_subframes /* i : number of subframes to render */ +#endif ); ivas_error ivas_td_binaural_renderer_ext( @@ -903,7 +909,12 @@ void ivas_SplitRenderer_getdiagdiff( void ivas_split_rend_bitstream_write_int32( ivas_split_rend_bits_t *pBits, int32_t val, int32_t bits ); int32_t ivas_split_rend_bitstream_read_int32( ivas_split_rend_bits_t *pBits, int32_t bits ); IVAS_QUATERNION ivas_split_rend_get_sf_rot_data( +#ifdef API_5MS + /* TODO(splitrend): clean up */ + const IVAS_QUATERNION headPositions[1], +#else const IVAS_QUATERNION headPositions[RENDERER_HEAD_POSITIONS_PER_FRAME], +#endif int16_t subframe_idx ); void ivas_rend_closeCldfbRend( CLDFB_REND_WRAPPER *pCldfbRend ); @@ -935,6 +946,9 @@ ivas_error ivas_rend_crendProcess( EFAP_HANDLE hEFAPdata, float *output[], /* i/o: input/output audio channels */ const int32_t output_Fs +#ifdef LIB_REND_API_5MS + ,const int16_t num_subframes /* i : number of subframes to render */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , const int16_t pos_idx @@ -1480,7 +1494,11 @@ void ivas_renderSplitUpdateNoCorrectionPoseData( ivas_error ivas_renderMultiBinToSplitBinaural( SPLIT_REND_WRAPPER *hSplitBin, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif const int32_t SplitRendBitRate, IVAS_SPLIT_REND_CODEC splitCodec, ivas_split_rend_bits_t *pBits, @@ -1495,7 +1513,11 @@ ivas_error ivas_renderMultiBinToSplitBinaural( void ivas_rend_CldfbSplitPreRendProcess( const BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], diff --git a/lib_rend/ivas_rotation.c b/lib_rend/ivas_rotation.c index c7d372d65d5ae08c6bbd7103f35008dfed804224..e726d9b9ca0b65f4f6b008a1b959c851194c66bd 100644 --- a/lib_rend/ivas_rotation.c +++ b/lib_rend/ivas_rotation.c @@ -48,15 +48,26 @@ * Local funtion declarations *-----------------------------------------------------------------------*/ -static ivas_error combine_external_and_head_orientations( IVAS_QUATERNION *headRotQuaternions, IVAS_VECTOR3 *listenerPos, +static ivas_error combine_external_and_head_orientations( + IVAS_QUATERNION *headRotQuaternions, + IVAS_VECTOR3 *listenerPos, #ifdef SPLIT_REND_WITH_HEAD_ROT - IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, /* i : split rend pose prediction axis*/ + IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, /* i : split rend pose prediction axis*/ #endif - int16_t numHeadRotQuaternions, - EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, - COMBINED_ORIENTATION_HANDLE hCombinedOrientationData ); +#ifndef API_5MS + int16_t numHeadRotQuaternions, +#endif + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData +); -static void external_target_interpolation( EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, const int16_t i ); +static void external_target_interpolation( + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData +#ifndef API_5MS + ,const int16_t i +#endif +); static bool are_orientations_same( const IVAS_QUATERNION *orientation1, const IVAS_QUATERNION *orientation2 ); @@ -81,7 +92,9 @@ ivas_error ivas_headTrack_open( } /* Initialization */ +#ifndef API_5MS ( *hHeadTrackData )->num_quaternions = 0; +#endif ( *hHeadTrackData )->lrSwitchInterpVal = 0.0f; ( *hHeadTrackData )->lrSwitchedCurrent = 0; ( *hHeadTrackData )->lrSwitchedNext = 0; @@ -357,14 +370,18 @@ void rotateFrame_shd( set_zero( SHrotmat[i], HEADROT_SHMAT_DIM ); } - /* calculate ambisonics rotation matrices for the previous and current frames */ #ifdef SPLIT_REND_WITH_HEAD_ROT SHrotmatgen( SHrotmat_prev, hCombinedOrientationData->Rmat_prev[0], shd_rot_max_order ); #else SHrotmatgen( SHrotmat_prev, hCombinedOrientationData->Rmat_prev, shd_rot_max_order ); #endif +#ifdef API_5MS + SHrotmatgen( SHrotmat, hCombinedOrientationData->Rmat, shd_rot_max_order ); +#else SHrotmatgen( SHrotmat, hCombinedOrientationData->Rmat[subframe_idx], shd_rot_max_order ); +#endif + for ( i = 0; i < subframe_len; i++ ) { @@ -416,11 +433,18 @@ void rotateFrame_shd( /* move Rmat to Rmat_prev */ for ( i = 0; i < 3; i++ ) { + mvr2r( +#ifdef API_5MS + hCombinedOrientationData->Rmat[i], +#else + hCombinedOrientationData->Rmat[subframe_idx][i], +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT - mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[0][i], 3 ); + hCombinedOrientationData->Rmat_prev[0][i], #else - mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[i], 3 ); + hCombinedOrientationData->Rmat_prev[i], #endif + 3 ); } return; @@ -513,7 +537,11 @@ void rotateFrame_sd( /* gains for current subframe rotation */ +#ifdef API_5MS + rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat, hTransSetup.is_planar_setup ); +#else rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat[subframe_idx], hTransSetup.is_planar_setup ); +#endif if ( hEFAPdata != NULL && ( hTransSetup.ls_azimuth[ch_in_woLFE] != azimuth || hTransSetup.ls_elevation[ch_in_woLFE] != elevation ) ) { efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP ); @@ -550,11 +578,18 @@ void rotateFrame_sd( /* move Rmat to Rmat_prev */ for ( i = 0; i < 3; i++ ) { + mvr2r( +#ifdef API_5MS + hCombinedOrientationData->Rmat[i], +#else + hCombinedOrientationData->Rmat[subframe_idx][i], +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT - mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[0][i], 3 ); + hCombinedOrientationData->Rmat_prev[0][i], #else - mvr2r( hCombinedOrientationData->Rmat[subframe_idx][i], hCombinedOrientationData->Rmat_prev[i], 3 ); + hCombinedOrientationData->Rmat_prev[i] #endif + 3 ); } /* copy to output */ @@ -783,7 +818,9 @@ ivas_error ivas_external_orientation_open( EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* o : external orientation handle */ ) { +#ifndef API_5MS int16_t i; +#endif IVAS_QUATERNION identity; identity.w = 1.0f; @@ -796,6 +833,13 @@ ivas_error ivas_external_orientation_open( } /* Enable head rotation and disable external orientation as default */ +#ifdef API_5MS + ( *hExtOrientationData )->enableHeadRotation = 1; + ( *hExtOrientationData )->enableExternalOrientation = 0; + ( *hExtOrientationData )->enableRotationInterpolation = 0; + ( *hExtOrientationData )->numFramesToTargetOrientation = 0; + ( *hExtOrientationData )->Quaternion = identity; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { ( *hExtOrientationData )->enableHeadRotation[i] = 1; @@ -804,7 +848,7 @@ ivas_error ivas_external_orientation_open( ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0; ( *hExtOrientationData )->Quaternions[i] = identity; } - +#endif return IVAS_ERR_OK; } @@ -841,7 +885,10 @@ ivas_error ivas_combined_orientation_open( COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* o : combined orientation handle */ ) { - int16_t i, j; +#ifndef API_5MS + int16_t i; +#endif + int16_t j; IVAS_QUATERNION identity; IVAS_VECTOR3 origo; #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -861,7 +908,11 @@ ivas_error ivas_combined_orientation_open( /* Initialization */ ( *hCombinedOrientationData )->interpolationCoefficient = 1.0f; ( *hCombinedOrientationData )->interpolationIncrement = 1.0f; +#ifdef API_5MS + ( *hCombinedOrientationData )->maximumFramesToTargetOrientation = 2000; +#else ( *hCombinedOrientationData )->maximumFramesToTargetOrientation = 500; +#endif ( *hCombinedOrientationData )->lrSwitchedNext = 0; ( *hCombinedOrientationData )->lrSwitchedCurrent = 0; ( *hCombinedOrientationData )->lrSwitchInterpVal = 0.0f; @@ -869,6 +920,19 @@ ivas_error ivas_combined_orientation_open( ( *hCombinedOrientationData )->Quaternions_ext_interpolation_start = identity; ( *hCombinedOrientationData )->Quaternions_ext_interpolation_target = identity; +#ifdef API_5MS + ( *hCombinedOrientationData )->enableCombinedOrientation = 0; + ( *hCombinedOrientationData )->Quaternion = identity; + ( *hCombinedOrientationData )->Quaternion_prev_headRot = identity; + ( *hCombinedOrientationData )->Quaternion_prev_extOrientation = identity; + ( *hCombinedOrientationData )->listenerPos = origo; + + for ( j = 0; j < 3; j++ ) + { + set_zero( ( *hCombinedOrientationData )->Rmat[j], 3 ); + ( *hCombinedOrientationData )->Rmat[j][j] = 1.0f; + } +#else /* API_5MS */ /* Initialise orientations to identity */ for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { @@ -877,7 +941,7 @@ ivas_error ivas_combined_orientation_open( #ifndef FIX_570_SF_EXT_ORIENTATION ( *hCombinedOrientationData )->Quaternions_prev_headRot[i] = identity; ( *hCombinedOrientationData )->Quaternions_prev_extOrientation[i] = identity; -#endif +#endif /* FIX_570_SF_EXT_ORIENTATION */ ( *hCombinedOrientationData )->listenerPos[i] = origo; for ( j = 0; j < 3; j++ ) @@ -886,6 +950,7 @@ ivas_error ivas_combined_orientation_open( ( *hCombinedOrientationData )->Rmat[i][j][j] = 1.0f; } } +#endif /* API_5MS */ #ifdef SPLIT_REND_WITH_HEAD_ROT for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ ) { @@ -961,18 +1026,25 @@ ivas_error combine_external_and_head_orientations_dec( #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis; #endif - IVAS_QUATERNION *headRotQuaternions = NULL; + IVAS_QUATERNION *headRotQuaternions = NULL; /* TODO(sgi): Rename to "headRotQuaternion" - it's a single value now */ IVAS_VECTOR3 *listenerPos = NULL; +#ifndef API_5MS int16_t numHeadRotQuaternions = 0; +#endif if ( hHeadTrackData != NULL ) { +#ifdef API_5MS + headRotQuaternions = &hHeadTrackData->Quaternion; + listenerPos = &hHeadTrackData->Pos; +#else numHeadRotQuaternions = hHeadTrackData->num_quaternions; if ( hHeadTrackData->num_quaternions >= 0 ) { headRotQuaternions = hHeadTrackData->Quaternions; listenerPos = hHeadTrackData->Pos; } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis; #endif @@ -984,11 +1056,18 @@ ivas_error combine_external_and_head_orientations_dec( } #endif - return combine_external_and_head_orientations( headRotQuaternions, listenerPos, + return combine_external_and_head_orientations( + headRotQuaternions, + listenerPos, #ifdef SPLIT_REND_WITH_HEAD_ROT - sr_pose_pred_axis, + sr_pose_pred_axis, +#endif +#ifndef API_5MS + numHeadRotQuaternions, #endif - numHeadRotQuaternions, hExtOrientationData, hCombinedOrientationData ); + hExtOrientationData, + hCombinedOrientationData + ); } @@ -1009,8 +1088,10 @@ ivas_error combine_external_and_head_orientations_rend( #endif IVAS_QUATERNION *headRotQuaternions = NULL; IVAS_VECTOR3 *listenerPos = NULL; +#ifndef API_5MS int16_t numHeadRotQuaternions = 0; int16_t i; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT sr_pose_pred_axis = DEFAULT_AXIS; @@ -1019,8 +1100,13 @@ ivas_error combine_external_and_head_orientations_rend( { if ( hHeadTrackData->headRotEnabled ) { +#ifdef LIB_REND_API_5MS + headRotQuaternions = &hHeadTrackData->headPosition; + listenerPos = &hHeadTrackData->Pos; +#else headRotQuaternions = hHeadTrackData->headPositions; listenerPos = hHeadTrackData->Pos; +#endif } #ifdef SPLIT_REND_WITH_HEAD_ROT sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis; @@ -1029,6 +1115,13 @@ ivas_error combine_external_and_head_orientations_rend( else if ( hExtOrientationData != NULL ) { /* Head rotation data not available, use the freezed value or disable */ +#ifdef API_5MS + if ( hExtOrientationData->enableHeadRotation != 2 ) + { + hExtOrientationData->enableHeadRotation = 0; + } + +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { if ( hExtOrientationData->enableHeadRotation[i] != 2 ) @@ -1036,13 +1129,20 @@ ivas_error combine_external_and_head_orientations_rend( hExtOrientationData->enableHeadRotation[i] = 0; } } +#endif } - return combine_external_and_head_orientations( headRotQuaternions, listenerPos, + return combine_external_and_head_orientations( + headRotQuaternions, + listenerPos, #ifdef SPLIT_REND_WITH_HEAD_ROT - sr_pose_pred_axis, + sr_pose_pred_axis, +#endif +#ifndef API_5MS + numHeadRotQuaternions, #endif - numHeadRotQuaternions, hExtOrientationData, hCombinedOrientationData ); + hExtOrientationData, + hCombinedOrientationData ); } @@ -1053,18 +1153,27 @@ ivas_error combine_external_and_head_orientations_rend( * NOTE that the external orientations are inversed. *------------------------------------------------------------------------*/ -static ivas_error combine_external_and_head_orientations( - IVAS_QUATERNION *headRotQuaternions, /* i : quaternions for head rotation */ - IVAS_VECTOR3 *listenerPos, /* i : listener position */ +ivas_error combine_external_and_head_orientations( +#ifdef LIB_REND_API_5MS + IVAS_QUATERNION *headRotQuaternion, /* i : quaternion for head rotation */ +#else + IVAS_QUATERNION *headRotQuaternions, /* i : quaternions for head rotation */ +#endif + IVAS_VECTOR3 *listenerPos, /* i : listener position */ #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, /* i : split rend pose prediction axis*/ #endif - int16_t numHeadRotQuaternions, /* i : number of head rotation quaternions */ - EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ - COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +#ifndef API_5MS + int16_t numHeadRotQuaternions, /* i : number of head rotation quaternions */ +#endif + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ ) { - int16_t i, j; +#ifndef API_5MS + int16_t i; +#endif + int16_t j; IVAS_QUATERNION identity; IVAS_VECTOR3 origo; @@ -1075,7 +1184,11 @@ static ivas_error combine_external_and_head_orientations( /* Form combined orientations or return if no data available */ if ( hCombinedOrientationData == NULL ) { +#ifdef LIB_REND_API_5MS + if ( headRotQuaternion != NULL || hExtOrientationData != NULL ) +#else if ( headRotQuaternions != NULL || hExtOrientationData != NULL ) +#endif { return IVAS_ERR_UNEXPECTED_NULL_POINTER; } @@ -1084,7 +1197,11 @@ static ivas_error combine_external_and_head_orientations( return IVAS_ERR_OK; } } +#ifdef LIB_REND_API_5MS + else if ( headRotQuaternion == NULL && hExtOrientationData == NULL ) +#else else if ( headRotQuaternions == NULL && hExtOrientationData == NULL ) +#endif { /* Reset the combined orientations and rotations */ hCombinedOrientationData->isInterpolationOngoing = FALSE; @@ -1092,6 +1209,18 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->interpolationIncrement = 1.0f; hCombinedOrientationData->Quaternions_ext_interpolation_start = identity; hCombinedOrientationData->Quaternions_ext_interpolation_target = identity; +#ifdef API_5MS + + hCombinedOrientationData->enableCombinedOrientation = 0; + hCombinedOrientationData->Quaternion = identity; + hCombinedOrientationData->listenerPos = origo; + + for ( j = 0; j < 3; j++ ) + { + set_zero( hCombinedOrientationData->Rmat[j], 3 ); + hCombinedOrientationData->Rmat[j][j] = 1.0f; + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { hCombinedOrientationData->enableCombinedOrientation[i] = 0; @@ -1104,10 +1233,23 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->Rmat[i][j][j] = 1.0f; } } +#endif } +#ifdef LIB_REND_API_5MS + else if ( hExtOrientationData == NULL && headRotQuaternion != NULL ) +#else else if ( hExtOrientationData == NULL && headRotQuaternions != NULL ) +#endif { /* Head rotation only */ +#ifdef API_5MS +#ifdef LIB_REND_API_5MS + hCombinedOrientationData->Quaternion = *headRotQuaternion; +#else + hCombinedOrientationData->Quaternion = *headRotQuaternions; +#endif + +#else if ( numHeadRotQuaternions >= 0 ) { for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) @@ -1115,11 +1257,47 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i]; } } +#endif } if ( hExtOrientationData != NULL ) { /* External orientations */ +#ifdef API_5MS + + if ( hExtOrientationData->enableRotationInterpolation == 1 && hExtOrientationData->enableExternalOrientation > 0 ) + { + if ( hCombinedOrientationData->isInterpolationOngoing == TRUE && hCombinedOrientationData->interpolationCoefficient <= 1.0f && are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternion ) == true ) + { + /* Continue interpolation */ + QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternion ); + hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement; + } + else + { + /* Stop interpolation or check for new interpolation */ + hCombinedOrientationData->isInterpolationOngoing = FALSE; + hCombinedOrientationData->interpolationCoefficient = 1.0f; + hCombinedOrientationData->interpolationIncrement = 1.0f; + external_target_interpolation( hExtOrientationData, hCombinedOrientationData ); + } + } + else + { + /* Interpolation disabled, use the current orientation values */ + + /* Use the most recent external orientation */ + if ( hExtOrientationData->enableExternalOrientation == 1 ) + { + hCombinedOrientationData->Quaternion = hExtOrientationData->Quaternion; + } + /* Use the freezed external orientation */ + else if ( hExtOrientationData->enableExternalOrientation == 2 ) + { + hCombinedOrientationData->Quaternion = hCombinedOrientationData->Quaternion_prev_extOrientation; + } + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { #ifdef FIX_570_SF_EXT_ORIENTATION @@ -1176,11 +1354,58 @@ static ivas_error combine_external_and_head_orientations( } } } +#endif } +#ifdef LIB_REND_API_5MS + if ( hExtOrientationData != NULL && headRotQuaternion != NULL ) +#else if ( hExtOrientationData != NULL && headRotQuaternions != NULL ) +#endif { /* Combine head and external orientations */ +#ifdef API_5MS + + /* Use the most recent head rotation */ + if ( hExtOrientationData->enableHeadRotation == 1 ) + { + if ( hExtOrientationData->enableExternalOrientation > 0 ) + { +#ifdef LIB_REND_API_5MS + QuaternionProduct( hCombinedOrientationData->Quaternion, *headRotQuaternion, &hCombinedOrientationData->Quaternion ); +#else + QuaternionProduct( hCombinedOrientationData->Quaternion, *headRotQuaternions, &hCombinedOrientationData->Quaternion ); +#endif + } + else + { +#ifdef LIB_REND_API_5MS + hCombinedOrientationData->Quaternion = *headRotQuaternion; +#else + hCombinedOrientationData->Quaternion = *headRotQuaternions; +#endif + } + } + /* Use the freezed head rotation */ + else if ( hExtOrientationData->enableHeadRotation == 2 ) + { + if ( hExtOrientationData->enableExternalOrientation > 0 ) + { + QuaternionProduct( hCombinedOrientationData->Quaternion, hCombinedOrientationData->Quaternion_prev_headRot, &hCombinedOrientationData->Quaternion ); + } + else + { + hCombinedOrientationData->Quaternion = hCombinedOrientationData->Quaternion_prev_headRot; + } + } + + /* Reset the combined orientations to identity */ + if ( hExtOrientationData->enableHeadRotation == 0 && hExtOrientationData->enableExternalOrientation == 0 ) + { + hCombinedOrientationData->Quaternion = identity; + } + +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { #ifdef FIX_570_SF_EXT_ORIENTATION @@ -1238,21 +1463,39 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->Quaternions[i] = identity; } } +#endif } +#ifdef LIB_REND_API_5MS + if ( headRotQuaternion != NULL || hExtOrientationData != NULL ) +#else if ( headRotQuaternions != NULL || hExtOrientationData != NULL ) +#endif { /* Calculate the combined rotation matrix */ +#ifdef API_5MS + QuatToRotMat( hCombinedOrientationData->Quaternion, hCombinedOrientationData->Rmat ); +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { QuatToRotMat( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Rmat[i] ); } +#endif } /* Save the current orientations */ if ( hExtOrientationData != NULL ) { -#ifdef FIX_570_SF_EXT_ORIENTATION +#ifdef API_5MS + if ( hExtOrientationData->enableExternalOrientation > 0 ) + { + hCombinedOrientationData->Quaternion_prev_extOrientation = hCombinedOrientationData->Quaternion; + } + else + { + hCombinedOrientationData->Quaternion_prev_extOrientation = identity; + } +#elif defined FIX_570_SF_EXT_ORIENTATION /* ToDo: ensure FIX_570_SF_EXT_ORIENTATION is correctly included in API_5MS */ if ( hExtOrientationData->enableExternalOrientation[MAX_PARAM_SPATIAL_SUBFRAMES - 1] > 0 ) { hCombinedOrientationData->Quaternion_prev_extOrientation = hExtOrientationData->Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES - 1]; @@ -1275,8 +1518,39 @@ static ivas_error combine_external_and_head_orientations( } #endif } +#ifdef LIB_REND_API_5MS + if ( headRotQuaternion != NULL ) +#else if ( headRotQuaternions != NULL ) +#endif { +#ifdef API_5MS + if ( hExtOrientationData != NULL ) + { + if ( hExtOrientationData->enableHeadRotation > 0 ) + { +#ifdef LIB_REND_API_5MS + hCombinedOrientationData->Quaternion_prev_headRot = *headRotQuaternion; +#else + hCombinedOrientationData->Quaternion_prev_headRot = *headRotQuaternions; +#endif + } + else + { + hCombinedOrientationData->Quaternion_prev_headRot = identity; + } + } + else + { +#ifdef LIB_REND_API_5MS + hCombinedOrientationData->Quaternion_prev_headRot = *headRotQuaternion; +#else + hCombinedOrientationData->Quaternion_prev_headRot = *headRotQuaternions; +#endif + } + hCombinedOrientationData->listenerPos = *listenerPos; + +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { #ifndef FIX_570_SF_EXT_ORIENTATION @@ -1305,11 +1579,20 @@ static ivas_error combine_external_and_head_orientations( #endif hCombinedOrientationData->listenerPos[i] = listenerPos[i]; } +#endif } /* Check if combined orientation is enabled */ +#ifdef LIB_REND_API_5MS + if ( headRotQuaternion != NULL && hExtOrientationData == NULL ) +#else if ( headRotQuaternions != NULL && hExtOrientationData == NULL ) +#endif { +#ifdef API_5MS + hCombinedOrientationData->enableCombinedOrientation = 1; + +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { if ( numHeadRotQuaternions >= 0 ) @@ -1321,9 +1604,24 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->enableCombinedOrientation[i] = 0; } } +#endif } +#ifdef LIB_REND_API_5MS + else if ( headRotQuaternion == NULL && hExtOrientationData != NULL ) +#else else if ( headRotQuaternions == NULL && hExtOrientationData != NULL ) +#endif { +#ifdef API_5MS + if ( hExtOrientationData->enableExternalOrientation > 0 ) + { + hCombinedOrientationData->enableCombinedOrientation = 1; + } + else + { + hCombinedOrientationData->enableCombinedOrientation = 0; + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { if ( hExtOrientationData->enableExternalOrientation[i] > 0 ) @@ -1335,9 +1633,24 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->enableCombinedOrientation[i] = 0; } } +#endif } +#ifdef LIB_REND_API_5MS + else if ( headRotQuaternion != NULL && hExtOrientationData != NULL ) +#else else if ( headRotQuaternions != NULL && hExtOrientationData != NULL ) +#endif { +#ifdef API_5MS + if ( hExtOrientationData->enableExternalOrientation > 0 || hExtOrientationData->enableHeadRotation > 0 ) + { + hCombinedOrientationData->enableCombinedOrientation = 1; + } + else + { + hCombinedOrientationData->enableCombinedOrientation = 0; + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { if ( hExtOrientationData->enableExternalOrientation[i] > 0 || ( hExtOrientationData->enableHeadRotation[i] > 0 && numHeadRotQuaternions >= 0 ) ) @@ -1349,13 +1662,18 @@ static ivas_error combine_external_and_head_orientations( hCombinedOrientationData->enableCombinedOrientation[i] = 0; } } +#endif } else { +#ifdef API_5MS + hCombinedOrientationData->enableCombinedOrientation = 0; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { hCombinedOrientationData->enableCombinedOrientation[i] = 0; } +#endif } #ifdef SPLIT_REND_WITH_HEAD_ROT hCombinedOrientationData->sr_pose_pred_axis = sr_pose_pred_axis; @@ -1371,27 +1689,57 @@ static ivas_error combine_external_and_head_orientations( * *------------------------------------------------------------------------*/ -static void external_target_interpolation( - EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ - COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */ - const int16_t i ) +void external_target_interpolation( + EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */ + COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */ +#ifndef API_5MS + , + const int16_t i +#endif +) { /* Sanity check for number of frames */ +#ifdef API_5MS + hExtOrientationData->numFramesToTargetOrientation = min( hExtOrientationData->numFramesToTargetOrientation, hCombinedOrientationData->maximumFramesToTargetOrientation ); + hExtOrientationData->numFramesToTargetOrientation = max( hExtOrientationData->numFramesToTargetOrientation, 0 ); +#else hExtOrientationData->numFramesToTargetOrientation[i] = min( hExtOrientationData->numFramesToTargetOrientation[i], hCombinedOrientationData->maximumFramesToTargetOrientation ); hExtOrientationData->numFramesToTargetOrientation[i] = max( hExtOrientationData->numFramesToTargetOrientation[i], 0 ); +#endif /* Interpolate from the current orientation to the target orientation */ +#ifdef API_5MS + if ( hExtOrientationData->numFramesToTargetOrientation > 0 ) +#else if ( hExtOrientationData->numFramesToTargetOrientation[i] > 0 ) +#endif { +#ifdef API_5MS + if ( are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternion ) == false ) +#else if ( are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ) == false ) +#endif { /* Target orientation is different from the previous target, update the values */ /* Set the received orientation as the target */ +#ifdef API_5MS + hCombinedOrientationData->Quaternions_ext_interpolation_target = hExtOrientationData->Quaternion; +#else hCombinedOrientationData->Quaternions_ext_interpolation_target = hExtOrientationData->Quaternions[i]; +#endif /* Use the most recent external orientation as the starting orientation */ -#ifdef FIX_570_SF_EXT_ORIENTATION +#ifdef API_5MS + if ( hExtOrientationData->enableExternalOrientation == 1 ) + { + hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_prev_extOrientation; + } + else if ( hExtOrientationData->enableExternalOrientation == 2 ) + { + hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_frozen_ext; + } +#elif defined FIX_570_SF_EXT_ORIENTATION if ( hExtOrientationData->enableExternalOrientation[i] == 1 ) { if ( i > 0 ) @@ -1412,13 +1760,21 @@ static void external_target_interpolation( #endif /* Calculate the interpolation increment and coefficient */ +#ifdef API_5MS + hCombinedOrientationData->interpolationIncrement = 1.0f / ( (float) hExtOrientationData->numFramesToTargetOrientation ); +#else hCombinedOrientationData->interpolationIncrement = 1.0f / ( (float) hExtOrientationData->numFramesToTargetOrientation[i] * (float) MAX_PARAM_SPATIAL_SUBFRAMES ); +#endif hCombinedOrientationData->interpolationCoefficient = hCombinedOrientationData->interpolationIncrement; } /* Interpolate */ hCombinedOrientationData->isInterpolationOngoing = TRUE; +#ifdef API_5MS + QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternion ); +#else QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternions[i] ); +#endif hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement; } else @@ -1427,7 +1783,11 @@ static void external_target_interpolation( hCombinedOrientationData->isInterpolationOngoing = FALSE; hCombinedOrientationData->interpolationCoefficient = 1.0f; hCombinedOrientationData->interpolationIncrement = 1.0f; +#ifdef API_5MS + hCombinedOrientationData->Quaternion = hExtOrientationData->Quaternion; +#else hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i]; +#endif } return; diff --git a/lib_rend/ivas_splitRendererPre.c b/lib_rend/ivas_splitRendererPre.c index 1b8a157f5bf3686aa4f002c8539a8a1670d0d90c..f98e09d2eac60d7b82eebe322858226d002eb8eb 100644 --- a/lib_rend/ivas_splitRendererPre.c +++ b/lib_rend/ivas_splitRendererPre.c @@ -1037,7 +1037,11 @@ static void ivas_SplitRenderer_code_md_huff( static void ivas_SplitRenderer_quant_code( const BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, ivas_split_rend_bits_t *pBits, const int16_t low_res_pre_rend_rot, @@ -1072,7 +1076,12 @@ static void ivas_SplitRenderer_quant_code( { int16_t angle; IVAS_QUATERNION head_pos_euler; +#ifdef API_5MS + /* FhG@Dolby: please review, this can be likely optimised */ + Quat2EulerDegree( headPosition, &head_pos_euler.z, &head_pos_euler.y, &head_pos_euler.x ); +#else Quat2EulerDegree( headPositions[sf_idx], &head_pos_euler.z, &head_pos_euler.y, &head_pos_euler.x ); +#endif angle = (int16_t) roundf( head_pos_euler.x ); angle += 180; ivas_split_rend_bitstream_write_int32( pBits, angle, IVAS_SPLIT_REND_HEAD_POSE_BITS ); @@ -1395,7 +1404,11 @@ void ivas_SplitRenderer_GetRotMd( void ivas_rend_CldfbSplitPreRendProcess( const BIN_HR_SPLIT_PRE_REND_HANDLE hBinHrSplitPreRend, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData, float Cldfb_In_BinReal[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_In_BinImag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], @@ -1414,7 +1427,11 @@ void ivas_rend_CldfbSplitPreRendProcess( ivas_SplitRenderer_quant_code( hBinHrSplitPreRend, +#ifdef API_5MS + headPosition, +#else headPositions, +#endif pMultiBinPoseData, pBits, low_res_pre_rend_rot, @@ -1897,7 +1914,11 @@ static ivas_error splitRendLc3plusEncodeAndWrite( static ivas_error ivas_renderMultiTDBinToSplitBinaural( SPLIT_REND_WRAPPER *hSplitBin, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif const int32_t SplitRendBitRate, ivas_split_rend_bits_t *pBits, const int16_t max_bands, @@ -1988,7 +2009,11 @@ static ivas_error ivas_renderMultiTDBinToSplitBinaural( actual_md_bits = pBits->bits_written; ivas_rend_CldfbSplitPreRendProcess( hSplitBin->hBinHrSplitPreRend, +#ifdef API_5MS + headPosition, +#else headPositions, +#endif &hSplitBin->multiBinPoseData, Cldfb_In_BinReal, Cldfb_In_BinImag, @@ -2095,7 +2120,11 @@ static void lc3plusTimeAlignCldfbPoseCorr( ivas_error ivas_renderMultiBinToSplitBinaural( SPLIT_REND_WRAPPER *hSplitBin, +#ifdef API_5MS + const IVAS_QUATERNION headPosition, +#else const IVAS_QUATERNION headPositions[MAX_PARAM_SPATIAL_SUBFRAMES], +#endif const int32_t SplitRendBitRate, IVAS_SPLIT_REND_CODEC splitCodec, ivas_split_rend_bits_t *pBits, @@ -2126,7 +2155,13 @@ ivas_error ivas_renderMultiBinToSplitBinaural( { /*TD input*/ /*if CLDFB handles have been allocated then assume valid multi binaural input in out[][] buffer and perform CLDFB analysis*/ - error = ivas_renderMultiTDBinToSplitBinaural( hSplitBin, headPositions, SplitRendBitRate, pBits, max_bands, out, + error = ivas_renderMultiTDBinToSplitBinaural( hSplitBin, +#ifdef API_5MS + headPosition, +#else + headPositions, +#endif + SplitRendBitRate, pBits, max_bands, out, low_res_pre_rend_rot, pcm_out ); pop_wmops(); return error; @@ -2145,7 +2180,11 @@ ivas_error ivas_renderMultiBinToSplitBinaural( actual_md_bits = pBits->bits_written; ivas_rend_CldfbSplitPreRendProcess( hSplitBin->hBinHrSplitPreRend, +#ifdef API_5MS + headPosition, +#else headPositions, +#endif &hSplitBin->multiBinPoseData, Cldfb_In_BinReal, Cldfb_In_BinImag, diff --git a/lib_rend/ivas_splitRenderer_utils.c b/lib_rend/ivas_splitRenderer_utils.c index b1068054f887b1a71ecdc61000b6c6c2524b66ef..df0863e773e724c0de9ea662deec975df39043c1 100644 --- a/lib_rend/ivas_splitRenderer_utils.c +++ b/lib_rend/ivas_splitRenderer_utils.c @@ -314,6 +314,7 @@ void ivas_split_rend_bitstream_write_int32( ivas_split_rend_bits_t *pBits, int32 return; } +#ifndef API_5MS IVAS_QUATERNION ivas_split_rend_get_sf_rot_data( const IVAS_QUATERNION headPositions[RENDERER_HEAD_POSITIONS_PER_FRAME], int16_t subframe_idx ) @@ -323,6 +324,7 @@ IVAS_QUATERNION ivas_split_rend_get_sf_rot_data( idx = ( subframe_idx * RENDERER_HEAD_POSITIONS_PER_FRAME ) / MAX_PARAM_SPATIAL_SUBFRAMES; return headPositions[idx]; } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG diff --git a/lib_rend/ivas_stat_rend.h b/lib_rend/ivas_stat_rend.h index 36c4a1783654583e146ceeaa66ccc38ad58840d6..a983c701fc804e74bbf7b1c92eb5b7dad9f3f941 100644 --- a/lib_rend/ivas_stat_rend.h +++ b/lib_rend/ivas_stat_rend.h @@ -787,9 +787,16 @@ typedef struct ivas_orient_trk_state_t typedef struct { int8_t headRotEnabled; +#ifdef LIB_REND_API_5MS + IVAS_QUATERNION headPosition; + IVAS_VECTOR3 Pos; + float crossfade_5ms[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES]; + float crossfade_20ms[L_FRAME48k]; +#else IVAS_QUATERNION headPositions[RENDERER_HEAD_POSITIONS_PER_FRAME]; IVAS_VECTOR3 Pos[RENDERER_HEAD_POSITIONS_PER_FRAME]; float crossfade[L_FRAME48k / RENDERER_HEAD_POSITIONS_PER_FRAME]; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis; #endif @@ -799,9 +806,14 @@ typedef struct typedef struct ivas_binaural_head_track_struct { +#ifdef API_5MS + IVAS_QUATERNION Quaternion; + IVAS_VECTOR3 Pos; +#else int16_t num_quaternions; IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES]; IVAS_VECTOR3 Pos[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif float Rmat[3][3]; float Rmat_prev[3][3]; @@ -826,12 +838,19 @@ typedef struct ivas_binaural_head_track_struct typedef struct ivas_external_orientation_struct { +#ifdef API_5MS + int8_t enableHeadRotation; /* 0 - disable, 1 - enable, 2 - freeze to previous rotation */ + int8_t enableExternalOrientation; /* 0 - disable, 1 - enable, 2 - freeze to previous orientation */ + int8_t enableRotationInterpolation; /* 0 - disable, 1 - enable */ + int16_t numFramesToTargetOrientation; /* Number of frames until target orientation is reached */ + IVAS_QUATERNION Quaternion; /* External orientation as a quaternion */ +#else int8_t enableHeadRotation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable, 2 - freeze to previous rotation */ int8_t enableExternalOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable, 2 - freeze to previous orientation */ int8_t enableRotationInterpolation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* 0 - disable, 1 - enable */ int16_t numFramesToTargetOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; /* Number of frames until target orientation is reached */ IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES]; /* External orientation in quaternions */ - +#endif } EXTERNAL_ORIENTATION_DATA, *EXTERNAL_ORIENTATION_HANDLE; /*----------------------------------------------------------------------------------* @@ -840,7 +859,11 @@ typedef struct ivas_external_orientation_struct typedef struct ivas_combined_orientation_struct { +#ifdef API_5MS + int16_t enableCombinedOrientation; +#else int16_t enableCombinedOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif float interpolationCoefficient; float interpolationIncrement; int16_t maximumFramesToTargetOrientation; @@ -848,16 +871,26 @@ typedef struct ivas_combined_orientation_struct uint8_t lrSwitchedCurrent; float lrSwitchInterpVal; bool isInterpolationOngoing; +#ifdef API_5MS + IVAS_QUATERNION Quaternion; + IVAS_QUATERNION Quaternion_prev_headRot; + IVAS_QUATERNION Quaternion_prev_extOrientation; +#else IVAS_QUATERNION Quaternions[MAX_PARAM_SPATIAL_SUBFRAMES]; #ifdef FIX_570_SF_EXT_ORIENTATION IVAS_QUATERNION Quaternion_prev_extOrientation; #else IVAS_QUATERNION Quaternions_prev_headRot[MAX_PARAM_SPATIAL_SUBFRAMES]; IVAS_QUATERNION Quaternions_prev_extOrientation[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif #endif IVAS_QUATERNION Quaternions_ext_interpolation_start; IVAS_QUATERNION Quaternions_ext_interpolation_target; +#ifdef API_5MS + float Rmat[3][3]; +#else float Rmat[MAX_PARAM_SPATIAL_SUBFRAMES][3][3]; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT float Rmat_prev[MAX_HEAD_ROT_POSES][3][3]; #else @@ -866,7 +899,11 @@ typedef struct ivas_combined_orientation_struct float chEneIIR[2][MASA_FREQUENCY_BANDS]; /* independent of the format. MASA bands are suitable for the task and readily available in ROM. */ float procChEneIIR[2][MASA_FREQUENCY_BANDS]; int16_t shd_rot_max_order; +#ifdef API_5MS + IVAS_VECTOR3 listenerPos; +#else IVAS_VECTOR3 listenerPos[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT IVAS_SPLIT_REND_ROT_AXIS sr_pose_pred_axis; #endif diff --git a/lib_rend/lib_rend.c b/lib_rend/lib_rend.c index 6dd53bdd025d3d6d75fe8c70f4b771223fa4c46d..f3878b0e2333899bed160c7079be9079f7e96737 100644 --- a/lib_rend/lib_rend.c +++ b/lib_rend/lib_rend.c @@ -70,7 +70,11 @@ #endif /* Frame size required when rendering to binaural */ +#ifdef LIB_REND_API_5MS +#define BINAURAL_RENDERING_FRAME_SIZE_MS 5 +#else #define BINAURAL_RENDERING_FRAME_SIZE_MS 20 +#endif /*-------------------------------------------------------------------* @@ -971,7 +975,11 @@ static ivas_error getNumNonLfeChannelsInSpeakerLayout( static ivas_error getMcConfigValues( IVAS_REND_AudioConfig inConfig, +#ifdef LIB_REND_API_5MS + const LSSETUP_CUSTOM_STRUCT *pInCustomLs, +#else LSSETUP_CUSTOM_STRUCT inCustomLs, +#endif const float **azimuth, const float **elevation, int16_t *lfe_idx, @@ -984,6 +992,22 @@ static ivas_error getMcConfigValues( switch ( inConfig ) { case IVAS_REND_AUDIO_CONFIG_LS_CUSTOM: +#ifdef LIB_REND_API_5MS + *azimuth = (const float *) &pInCustomLs->ls_azimuth; + *elevation = (const float *) &pInCustomLs->ls_elevation; + if ( pInCustomLs->num_lfe > 0 ) + { + *lfe_idx = pInCustomLs->lfe_idx[0]; + } + for ( i = 0; i < pInCustomLs->num_spk; i++ ) + { + if ( pInCustomLs->ls_elevation[i] != 0 ) + { + *is_planar = 0; + break; + } + } +#else *azimuth = (const float *) &inCustomLs.ls_azimuth; *elevation = (const float *) &inCustomLs.ls_elevation; if ( inCustomLs.num_lfe > 0 ) @@ -998,6 +1022,7 @@ static ivas_error getMcConfigValues( break; } } +#endif break; case IVAS_REND_AUDIO_CONFIG_MONO: case IVAS_REND_AUDIO_CONFIG_STEREO: @@ -1160,6 +1185,25 @@ static ivas_error initHeadRotation( /* Head rotation is enabled by default */ hIvasRend->headRotData.headRotEnabled = 1; +#ifdef LIB_REND_API_5MS + /* Initialize 5ms crossfade */ + crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES; /* TODO(sgi): @tmu why do we assume 48 kHz here? */ + tmp = 1.f / ( crossfade_len - 1 ); + for ( i = 0; i < crossfade_len; i++ ) + { + hIvasRend->headRotData.crossfade_5ms[i] = i * tmp; + } + /* Initialize 20ms crossfade */ + crossfade_len = L_FRAME48k; /* TODO(sgi): @tmu why do we assume 48 kHz here? */ + tmp = 1.f / ( crossfade_len - 1 ); + for ( i = 0; i < crossfade_len; i++ ) + { + hIvasRend->headRotData.crossfade_20ms[i] = i * tmp; + } + + /* Initialize with unit quaternion */ + hIvasRend->headRotData.headPosition = quaternionInit(); +#else /* Initialize 5ms crossfade */ crossfade_len = L_FRAME48k / RENDERER_HEAD_POSITIONS_PER_FRAME; tmp = 1.f / ( crossfade_len - 1 ); @@ -1173,6 +1217,7 @@ static ivas_error initHeadRotation( { hIvasRend->headRotData.headPositions[i] = quaternionInit(); } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS; #endif @@ -3217,8 +3262,11 @@ static DecoderDummy *initDecoderDummy( decDummy->hDecoderConfig->output_Fs = sampleRate; decDummy->hDecoderConfig->nchan_out = numOutChannels; decDummy->hDecoderConfig->Opt_Headrotation = 0; +#ifdef API_5MS + decDummy->hDecoderConfig->tsm_active = 0; +#else decDummy->hDecoderConfig->voip_active = 0; - +#endif decDummy->hBinRenderer = NULL; #ifdef SPLIT_REND_WITH_HEAD_ROT decDummy->splitBinRend.hSplitRendBits = NULL; @@ -3257,6 +3305,12 @@ static DecoderDummy *initDecoderDummy( set_zero( decDummy->hHeadTrackData->chEneIIR[1], MASA_FREQUENCY_BANDS ); set_zero( decDummy->hHeadTrackData->procChEneIIR[0], MASA_FREQUENCY_BANDS ); set_zero( decDummy->hHeadTrackData->procChEneIIR[1], MASA_FREQUENCY_BANDS ); +#ifdef API_5MS + decDummy->hHeadTrackData->Quaternion.w = 1.0f; + decDummy->hHeadTrackData->Quaternion.x = 0.0f; + decDummy->hHeadTrackData->Quaternion.y = 0.0f; + decDummy->hHeadTrackData->Quaternion.z = 0.0f; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ ) { decDummy->hHeadTrackData->Quaternions[i].w = 1.0f; @@ -3264,7 +3318,7 @@ static DecoderDummy *initDecoderDummy( decDummy->hHeadTrackData->Quaternions[i].y = 0.0f; decDummy->hHeadTrackData->Quaternions[i].z = 0.0f; } - decDummy->hHeadTrackData->num_quaternions = 0; +#endif decDummy->hHeadTrackData->lrSwitchInterpVal = 0.0f; decDummy->hHeadTrackData->lrSwitchedCurrent = 0; decDummy->hHeadTrackData->lrSwitchedNext = 0; @@ -3395,6 +3449,12 @@ static void freeDecoderDummy( { free( pDecDummy->hCombinedOrientationData ); } +#ifdef LIB_REND_FIX_HRTFPARAMBIN_MEMLEAK + if ( pDecDummy->hHrtfParambin != NULL ) + { + free( pDecDummy->hHrtfParambin ); + } +#endif ivas_render_config_close( &pDecDummy->hRenderConfig ); @@ -4629,7 +4689,7 @@ ivas_error IVAS_REND_FeedInputAudio( if ( inputAudio.config.numSamplesPerChannel <= 0 || MAX_BUFFER_LENGTH_PER_CHANNEL < inputAudio.config.numSamplesPerChannel ) #endif { - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" ); } if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels ) @@ -4645,8 +4705,7 @@ ivas_error IVAS_REND_FeedInputAudio( inputAudio.config.numSamplesPerChannel * 1000 != BINAURAL_RENDERING_FRAME_SIZE_MS * hIvasRend->sampleRateOut ) #endif { - /* Binaural rendering requires specific frame size */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" ); } if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK ) @@ -4987,16 +5046,23 @@ int16_t IVAS_REND_FeedRenderConfig( *-------------------------------------------------------------------*/ ivas_error IVAS_REND_SetHeadRotation( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ +#ifdef LIB_REND_API_5MS + const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */ + const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ +#else const IVAS_QUATERNION headRot[RENDERER_HEAD_POSITIONS_PER_FRAME], /* i : head orientations for next rendering call */ const IVAS_VECTOR3 Pos[RENDERER_HEAD_POSITIONS_PER_FRAME] /* i : listener positions for next rendering call */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , IVAS_SPLIT_REND_ROT_AXIS rot_axis #endif ) { +#ifndef LIB_REND_API_5MS int16_t i; +#endif IVAS_QUATERNION rotQuat; /* Validate function arguments */ @@ -5011,6 +5077,20 @@ ivas_error IVAS_REND_SetHeadRotation( return IVAS_ERR_INVALID_OUTPUT_FORMAT; } +#ifdef LIB_REND_API_5MS + /* check for Euler angle signaling */ + if ( headRot.w == -3.0f ) + { + Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat ); + } + else + { + rotQuat = headRot; + } + + ivas_orient_trk_Process( hIvasRend->headRotData.hOrientationTracker, rotQuat, FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES, &hIvasRend->headRotData.headPosition ); + hIvasRend->headRotData.Pos = Pos; +#else if ( headRot == NULL ) { #ifdef SPLIT_REND_WITH_HEAD_ROT @@ -5065,6 +5145,7 @@ ivas_error IVAS_REND_SetHeadRotation( hIvasRend->headRotData.Pos[i] = Pos[i]; } } +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT hIvasRend->headRotData.sr_pose_pred_axis = rot_axis; @@ -5073,6 +5154,22 @@ ivas_error IVAS_REND_SetHeadRotation( return IVAS_ERR_OK; } +#ifdef LIB_REND_API_5MS +ivas_error IVAS_REND_DisableHeadRotation( + IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */ +) +{ + /* Validate function arguments */ + if ( hIvasRend == NULL ) + { + return IVAS_ERR_UNEXPECTED_NULL_POINTER; + } + + hIvasRend->headRotData.headRotEnabled = 0; + return IVAS_ERR_OK; +} +#endif + #ifdef SPLIT_REND_WITH_HEAD_ROT ivas_error IVAS_REND_SetSplitRendBFI( IVAS_REND_HANDLE hIvasRend, @@ -5209,15 +5306,24 @@ ivas_error IVAS_REND_SetReferenceVector( *---------------------------------------------------------------------*/ ivas_error IVAS_REND_SetExternalOrientation( - IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_QUATERNION *orientation, /* i : external orientation data */ + IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ + IVAS_QUATERNION *orientation, /* i : external orientation data */ +#ifdef LIB_REND_API_5MS + int8_t enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ /* TODO(sgi): make independent of framing */ +#else int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#endif ) { +#ifndef LIB_REND_API_5MS int16_t i; +#endif /* Validate function arguments */ if ( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL ) @@ -5227,22 +5333,45 @@ ivas_error IVAS_REND_SetExternalOrientation( if ( orientation == NULL ) { +#ifdef API_5MS + hIvasRend->hExternalOrientationData->enableExternalOrientation = 0; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) { hIvasRend->hExternalOrientationData->enableExternalOrientation[i] = 0; } +#endif } else { +#ifdef LIB_REND_API_5MS + QuaternionInverse( *orientation, &hIvasRend->hExternalOrientationData->Quaternion ); + + hIvasRend->hExternalOrientationData->enableHeadRotation = enableHeadRotation; + hIvasRend->hExternalOrientationData->enableExternalOrientation = enableExternalOrientation; + hIvasRend->hExternalOrientationData->enableRotationInterpolation = enableRotationInterpolation; + hIvasRend->hExternalOrientationData->numFramesToTargetOrientation = numFramesToTargetOrientation; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) { +#ifdef API_5MS + /* just fix compilation issues, ToDo: change ext renderer also to 5ms */ + QuaternionInverse( orientation[i], &hIvasRend->hExternalOrientationData->Quaternion ); + + hIvasRend->hExternalOrientationData->enableHeadRotation = enableHeadRotation[i]; + hIvasRend->hExternalOrientationData->enableExternalOrientation = enableExternalOrientation[i]; + hIvasRend->hExternalOrientationData->enableRotationInterpolation = enableRotationInterpolation[i]; + hIvasRend->hExternalOrientationData->numFramesToTargetOrientation = numFramesToTargetOrientation[i]; +#else QuaternionInverse( orientation[i], &hIvasRend->hExternalOrientationData->Quaternions[i] ); hIvasRend->hExternalOrientationData->enableHeadRotation[i] = enableHeadRotation[i]; hIvasRend->hExternalOrientationData->enableExternalOrientation[i] = enableExternalOrientation[i]; hIvasRend->hExternalOrientationData->enableRotationInterpolation[i] = enableRotationInterpolation[i]; hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[i] = numFramesToTargetOrientation[i]; +#endif } +#endif } return IVAS_ERR_OK; @@ -5279,7 +5408,9 @@ ivas_error IVAS_REND_GetCombinedOrientation( IVAS_QUATERNION *pOrientation /* i/o: Quaternion pointer processed orientation */ ) { +#ifndef LIB_REND_API_5MS int16_t i; +#endif if ( hIvasRend == NULL || pOrientation == NULL ) { @@ -5288,10 +5419,19 @@ ivas_error IVAS_REND_GetCombinedOrientation( if ( hIvasRend->hCombinedOrientationData != NULL ) { +#ifdef LIB_REND_API_5MS + *pOrientation = hIvasRend->hCombinedOrientationData->Quaternion; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; ++i ) { +#ifdef API_5MS + /* fix compilation only,ToDo adapt ext renderer to 5ms , this functions looks stale anyway */ + pOrientation[i] = hIvasRend->hCombinedOrientationData->Quaternion; +#else pOrientation[i] = hIvasRend->hCombinedOrientationData->Quaternions[i]; +#endif } +#endif } return IVAS_ERR_OK; @@ -5387,10 +5527,34 @@ static void renderBufferChannel( return; } +#ifdef API_5MS +static ivas_error chooseCrossfade( const IVAS_REND_HeadRotData *headRotData, int16_t numSamplesPerChannel, const float **pCrossfade ) +{ + if ( numSamplesPerChannel == L_FRAME48k ) + { + *pCrossfade = headRotData->crossfade_20ms; + } + else if ( numSamplesPerChannel == L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES ) + { + *pCrossfade = headRotData->crossfade_5ms; + } + else + { + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Only 5 and 20 ms framing is supported" ); + } + + return IVAS_ERR_OK; +} +#endif + static ivas_error rotateFrameMc( - IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */ - IVAS_REND_AudioConfig inConfig, /* i : Input Audio config */ - LSSETUP_CUSTOM_STRUCT inCustomLs, /* i : Input Custom LS setup */ + IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */ + IVAS_REND_AudioConfig inConfig, /* i : Input Audio config */ +#ifdef LIB_REND_API_5MS + const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */ +#else + LSSETUP_CUSTOM_STRUCT inCustomLs, /* i : Input Custom LS setup */ +#endif const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */ const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */ rotation_gains gains_prev, /* i/o: Previous frame rotation gains */ @@ -5400,7 +5564,11 @@ static ivas_error rotateFrameMc( { int16_t i; int16_t j; +#ifdef LIB_REND_API_5MS + const float *crossfade; +#else int16_t subframe_idx, subframe_len; +#endif int16_t azimuth, elevation; int16_t is_planar_setup, lfe_idx; int16_t nchan; @@ -5415,6 +5583,13 @@ static ivas_error rotateFrameMc( push_wmops( "rotateFrameMc" ); +#ifdef LIB_REND_API_5MS + if ( ( error = chooseCrossfade( headRotData, inAudio.config.numSamplesPerChannel, &crossfade ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + if ( inConfig != IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) { if ( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ) != IVAS_ERR_OK ) @@ -5424,10 +5599,20 @@ static ivas_error rotateFrameMc( } else { +#ifdef LIB_REND_API_5MS + nchan = pInCustomLs->num_spk + pInCustomLs->num_lfe; +#else nchan = inCustomLs.num_spk + inCustomLs.num_lfe; +#endif } - if ( ( error = getMcConfigValues( inConfig, inCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ) != IVAS_ERR_OK ) + if ( ( error = getMcConfigValues( inConfig, +#ifdef LIB_REND_API_5MS + pInCustomLs, +#else + inCustomLs, +#endif + &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ) != IVAS_ERR_OK ) { return error; } @@ -5439,17 +5624,25 @@ static ivas_error rotateFrameMc( gains[ch_in][ch_in] = 1.f; } +#ifndef LIB_REND_API_5MS + /* TODO(sgi): @tmu please review changes in this function */ /* subframe loop */ subframe_len = inAudio.config.numSamplesPerChannel / RENDERER_HEAD_POSITIONS_PER_FRAME; for ( subframe_idx = 0; subframe_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; subframe_idx++ ) { +#endif for ( i = 0; i < 3; i++ ) { if ( hCombinedOrientationData != NULL ) { for ( j = 0; j < 3; j++ ) { - Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; +#ifdef API_5MS + /* fix compiling only, ToDo adapt ext renderer to 5ms */ + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[i][j]; +#else + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; +#endif } } else @@ -5499,16 +5692,29 @@ static ivas_error rotateFrameMc( { for ( ch_in = 0; ch_in < nchan; ch_in++ ) { - writePtr = getSmplPtr( outAudio, ch_out, subframe_idx * subframe_len ); - readPtr = getSmplPtr( inAudio, ch_in, subframe_idx * subframe_len ); +#ifdef LIB_REND_API_5MS + writePtr = getSmplPtr( outAudio, ch_out, 0 ); + readPtr = getSmplPtr( inAudio, ch_in, 0 ); /* crossfade with previous rotation gains */ - for ( i = 0; i < subframe_len; i++ ) + for ( i = 0; i < inAudio.config.numSamplesPerChannel; i++ ) { *writePtr++ += - ( *readPtr ) * ( ( 1 - headRotData->crossfade[i] ) * gains_prev[ch_in][ch_out] ) + - ( *readPtr ) * ( headRotData->crossfade[i] * gains[ch_in][ch_out] ); + ( *readPtr ) * ( ( 1 - crossfade[i] ) * gains_prev[ch_in][ch_out] ) + + ( *readPtr ) * ( crossfade[i] * gains[ch_in][ch_out] ); readPtr++; } +#else + writePtr = getSmplPtr( outAudio, ch_out, subframe_idx * subframe_len ); + readPtr = getSmplPtr( inAudio, ch_in, subframe_idx * subframe_len ); + /* crossfade with previous rotation gains */ + for ( i = 0; i < subframe_len; i++ ) + { + *writePtr++ += + ( *readPtr ) * ( ( 1 - headRotData->crossfade[i] ) * gains_prev[ch_in][ch_out] ) + + ( *readPtr ) * ( headRotData->crossfade[i] * gains[ch_in][ch_out] ); + readPtr++; + } +#endif } } @@ -5517,7 +5723,9 @@ static ivas_error rotateFrameMc( { mvr2r( gains[i], gains_prev[i], nchan ); } +#ifndef LIB_REND_API_5MS } +#endif pop_wmops(); @@ -5536,8 +5744,12 @@ static ivas_error rotateFrameSba( int16_t i, l, n, m; int16_t m1, m2; int16_t shd_rot_max_order; +#ifdef LIB_REND_API_5MS + const float *crossfade; +#else int16_t subframe_idx, subframe_len; - float *writePtr; +#endif + float *readPtr, *writePtr; rotation_matrix Rmat; float tmpRot[2 * HEADROT_ORDER + 1]; rotation_gains gains; @@ -5547,15 +5759,25 @@ static ivas_error rotateFrameSba( push_wmops( "rotateFrameSba" ); +#ifdef LIB_REND_API_5MS + if ( ( error = chooseCrossfade( headRotData, inAudio.config.numSamplesPerChannel, &crossfade ) ) != IVAS_ERR_OK ) + { + return error; + } +#endif + if ( ( error = getAmbisonicsOrder( inConfig, &shd_rot_max_order ) ) != IVAS_ERR_OK ) { return error; } +#ifndef LIB_REND_API_5MS + /* TODO(sgi): @tmu please review changes in this function */ /* subframe loop */ subframe_len = inAudio.config.numSamplesPerChannel / RENDERER_HEAD_POSITIONS_PER_FRAME; for ( subframe_idx = 0; subframe_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; subframe_idx++ ) { +#endif /* initialize rotation matrices with zeros */ for ( i = 0; i < HEADROT_SHMAT_DIM; i++ ) { @@ -5568,7 +5790,12 @@ static ivas_error rotateFrameSba( { for ( l = 0; l < 3; l++ ) { - Rmat[i][l] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][l]; +#ifdef API_5MS + /* fix compilation only, ToDo adapt ext renderer to 5ms */ + Rmat[i][l] = ( *hCombinedOrientationData )->Rmat[i][l]; +#else + Rmat[i][l] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][l]; +#endif } } else @@ -5582,10 +5809,19 @@ static ivas_error rotateFrameSba( /* calculate ambisonics rotation matrices for the previous and current frames */ SHrotmatgen( gains, Rmat, shd_rot_max_order ); - for ( i = 0; i < subframe_len; i++ ) +#ifdef LIB_REND_API_5MS + for ( i = 0; i < inAudio.config.numSamplesPerChannel; i++ ) +#else + for ( i = 0; i < subframe_len; i++ ) +#endif { +#ifdef API_5MS + idx = i; + cf = crossfade[i]; +#else idx = subframe_idx * subframe_len + i; cf = headRotData->crossfade[i]; +#endif oneminuscf = 1 - cf; /* As the rotation matrix becomes block diagonal in a SH basis, we can*/ /* apply each angular-momentum block individually to save complexity. */ @@ -5602,15 +5838,47 @@ static ivas_error rotateFrameSba( for ( m = m1; m < m2; m++ ) { - val = inAudio.data[m * inAudio.config.numSamplesPerChannel + idx]; +// sgi@bay sgi2tmu to be verified how to resolve this correctly +// <<<<<<< HEAD +// #ifdef LIB_REND_API_5MS +// readPtr = getSmplPtr( inAudio, m, i ); +// /* crossfade with previous rotation gains */ +// tmpRot[n - m1] += crossfade[i] * gains[n][m] * ( *readPtr ) + +// ( 1 - crossfade[i] ) * gains_prev[n][m] * ( *readPtr ); +// #else +// readPtr = getSmplPtr( inAudio, m, subframe_idx * subframe_len + i ); +// /* crossfade with previous rotation gains */ +// tmpRot[n - m1] += headRotData->crossfade[i] * gains[n][m] * ( *readPtr ) + +// ( 1 - headRotData->crossfade[i] ) * gains_prev[n][m] * ( *readPtr ); +// #endif +// ======= +// val = inAudio.data[m * inAudio.config.numSamplesPerChannel + idx]; +// /* crossfade with previous rotation gains */ +// tmpRot[n - m1] += ( cf * gains[n][m] * val + oneminuscf * gains_prev[n][m] * val ); +// >>>>>>> main +// tmp merge: +#ifdef LIB_REND_API_5MS + readPtr = getSmplPtr( inAudio, m, i ); /* crossfade with previous rotation gains */ - tmpRot[n - m1] += ( cf * gains[n][m] * val + oneminuscf * gains_prev[n][m] * val ); + tmpRot[n - m1] += crossfade[i] * gains[n][m] * ( *readPtr ) + + ( 1 - crossfade[i] ) * gains_prev[n][m] * ( *readPtr ); +#else + readPtr = getSmplPtr( inAudio, m, subframe_idx * subframe_len + i ); + /* crossfade with previous rotation gains */ + tmpRot[n - m1] += headRotData->crossfade[i] * gains[n][m] * ( *readPtr ) + + ( 1 - headRotData->crossfade[i] ) * gains_prev[n][m] * ( *readPtr ); +#endif +// merge end } } /* write back the result */ for ( n = m1; n < m2; n++ ) { - writePtr = getSmplPtr( outAudio, n, subframe_idx * subframe_len + i ); +#ifdef LIB_REND_API_5MS + writePtr = getSmplPtr( outAudio, n, i ); +#else + writePtr = getSmplPtr( outAudio, n, subframe_idx * subframe_len + i ); +#endif ( *writePtr ) = tmpRot[n - m1]; } m1 = m2; @@ -5638,7 +5906,9 @@ static ivas_error rotateFrameSba( { mvr2r( gains[i], gains_prev[i], HEADROT_SHMAT_DIM ); } +#ifndef LIB_REND_API_5MS } +#endif pop_wmops(); @@ -5683,13 +5953,25 @@ static ivas_error renderIsmToBinaural( return IVAS_ERR_OK; } +#ifdef LIB_REND_API_5MS +static int16_t num_subframes_in_buffer( const IVAS_REND_AudioBuffer *buffer, int32_t sampleRate ) +{ +#ifdef DEBUGGING + assert( buffer->config.numSamplesPerChannel % ( sampleRate / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) == 0 ); +#endif + return (int16_t) ( buffer->config.numSamplesPerChannel / ( sampleRate / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES ) ); +} +#endif + static ivas_error renderIsmToBinauralRoom( input_ism *ismInput, IVAS_REND_AudioBuffer outAudio ) { int16_t i; int16_t azi_rot, ele_rot; +#ifndef LIB_REND_API_5MS int16_t subframe_idx, subframe_len; +#endif int16_t tmp; rotation_matrix Rmat; float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; @@ -5716,32 +5998,54 @@ static ivas_error renderIsmToBinauralRoom( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + /* fix compilation only, ToDo adapt ext renderer to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { + if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) { combinedOrientationEnabled = 1; break; } } +#endif } if ( combinedOrientationEnabled ) { +#ifndef LIB_REND_API_5MS subframe_len = ismInput->base.inputBuffer.config.numSamplesPerChannel / RENDERER_HEAD_POSITIONS_PER_FRAME; // for ( subframe_idx = 0; subframe_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; subframe_idx++ ) for ( subframe_idx = 0; subframe_idx < 1; subframe_idx++ ) { +#endif for ( i = 0; i < 3; i++ ) { - if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] ) +#ifdef API_5MS + /* at least this looks like it is adapted to 5ms already since it "loops" only over the first subframe, ToDo needs to be checked */ + if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation ) { for ( j = 0; j < 3; j++ ) { - Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[i][j]; } } +#else + if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] ) + { + for ( j = 0; j < 3; j++ ) + { + Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j]; + } + } +#endif else { /* Set to identity */ @@ -5749,8 +6053,10 @@ static ivas_error renderIsmToBinauralRoom( Rmat[i][i] = 1.0f; } } +#ifndef LIB_REND_API_5MS } (void) subframe_len; // avoid warning +#endif } /* TODO tmu : see issue #518 */ @@ -5811,11 +6117,15 @@ static ivas_error renderIsmToBinauralRoom( if ( ( error = ivas_rend_crendProcess( ismInput->crendWrapper, AUDIO_CONFIG_7_1_4, AUDIO_CONFIG_BINAURAL_ROOM_IR, NULL, NULL, NULL, NULL, p_tmpRendBuffer, *ismInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *ismInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 #endif - ) ) != IVAS_ERR_OK ) + ) ) != IVAS_ERR_OK ) { return error; } @@ -5995,7 +6305,11 @@ static ivas_error renderIsmToSplitBinaural( int16_t pos_idx; const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData; const SPLIT_REND_WRAPPER *pSplitRendWrapper; +#ifdef API_5MS + IVAS_QUATERNION originalHeadRot; +#else IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES]; +#endif float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k]; int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel; COMBINED_ORIENTATION_HANDLE pCombinedOrientationData; @@ -6037,17 +6351,25 @@ static ivas_error renderIsmToSplitBinaural( if ( pMultiBinPoseData->poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { +#ifdef API_5MS + pCombinedOrientationData->Quaternion = pCombinedOrientationData->Quaternion; +#else for ( i = 1; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { pCombinedOrientationData->Quaternions[i] = pCombinedOrientationData->Quaternions[0]; } +#endif } /* Save current head positions */ +#ifdef API_5MS + originalHeadRot = pCombinedOrientationData->Quaternion; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { originalHeadRot[i] = pCombinedOrientationData->Quaternions[i]; } +#endif /* Copy input audio to a processing buffer. */ copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing ); @@ -6057,6 +6379,26 @@ static ivas_error renderIsmToSplitBinaural( /* Update head positions */ if ( pos_idx != 0 ) { +#ifdef API_5MS + if ( originalHeadRot.w == -3.0f ) + { + pCombinedOrientationData->Quaternion.w = -3.0f; + pCombinedOrientationData->Quaternion.x = originalHeadRot.x + pMultiBinPoseData->relative_head_poses[pos_idx][0]; + pCombinedOrientationData->Quaternion.y = originalHeadRot.y + pMultiBinPoseData->relative_head_poses[pos_idx][1]; + pCombinedOrientationData->Quaternion.z = originalHeadRot.z + pMultiBinPoseData->relative_head_poses[pos_idx][2]; + } + else + { + pCombinedOrientationData->Quaternion.w = -3.0f; + Quat2EulerDegree( originalHeadRot, + &pCombinedOrientationData->Quaternion.z, + &pCombinedOrientationData->Quaternion.y, + &pCombinedOrientationData->Quaternion.x ); + pCombinedOrientationData->Quaternion.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + pCombinedOrientationData->Quaternion.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + pCombinedOrientationData->Quaternion.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + } +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { if ( originalHeadRot[i].w == -3.0f ) @@ -6078,6 +6420,7 @@ static ivas_error renderIsmToSplitBinaural( pCombinedOrientationData->Quaternions[i].z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; } } +#endif } /* Render */ @@ -6127,10 +6470,14 @@ static ivas_error renderIsmToSplitBinaural( copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing ); } /* Restore original head rotation */ +#ifdef API_5MS + pCombinedOrientationData->Quaternion = originalHeadRot; +#else for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; ++i ) { pCombinedOrientationData->Quaternions[i] = originalHeadRot[i]; } +#endif accumulate2dArrayToBuffer( tmpBinaural, &outAudio ); pop_wmops(); @@ -6168,8 +6515,7 @@ static ivas_error renderInputIsm( if ( ismInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) { - /* Mismatch between the number of input samples vs number of requested output samples - currently not allowed */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } ismInput->base.numNewSamplesPerChannel = 0; @@ -6386,7 +6732,9 @@ static ivas_error renderMcToBinaural( IVAS_REND_AudioBuffer tmpRotBuffer; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; int8_t combinedOrientationEnabled; +#ifndef API_5MS int16_t subframe_idx; +#endif float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS]; int16_t i; @@ -6403,6 +6751,14 @@ static ivas_error renderMcToBinaural( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + /* fix compiling only, ToDo ext renderer needs to adapted to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } + +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) @@ -6411,6 +6767,7 @@ static ivas_error renderMcToBinaural( break; } } +#endif } if ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled @@ -6440,7 +6797,13 @@ static ivas_error renderMcToBinaural( tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, + if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, +#ifdef LIB_REND_API_5MS + &mcInput->customLsInput, +#else + mcInput->customLsInput, +#endif + mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { @@ -6458,12 +6821,15 @@ static ivas_error renderMcToBinaural( /* call CREND */ if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, getIvasAudioConfigFromRendAudioConfig( mcInput->base.inConfig ), getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 #endif - ) ) != IVAS_ERR_OK ) - + ) ) != IVAS_ERR_OK ) { return error; } @@ -6499,7 +6865,9 @@ static ivas_error renderMcToBinauralRoom( int16_t i; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; int8_t combinedOrientationEnabled; +#ifndef API_5MS int16_t subframe_idx; +#endif for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ ) { @@ -6514,6 +6882,13 @@ static ivas_error renderMcToBinauralRoom( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + /* fix compiling only, ToDo ext renderer needs to adapted to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) @@ -6522,6 +6897,7 @@ static ivas_error renderMcToBinauralRoom( break; } } +#endif } if ( ( mcInput->hReverb != NULL && outConfig == IVAS_REND_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && ( ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) ) ) ) @@ -6548,7 +6924,13 @@ static ivas_error renderMcToBinauralRoom( tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, + if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, +#ifdef LIB_REND_API_5MS + &mcInput->customLsInput, +#else + mcInput->customLsInput, +#endif + mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { @@ -6566,11 +6948,15 @@ static ivas_error renderMcToBinauralRoom( /* call CREND */ if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, getIvasAudioConfigFromRendAudioConfig( mcInput->base.inConfig ), getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 #endif - ) ) != IVAS_ERR_OK ) + ) ) != IVAS_ERR_OK ) { return error; } @@ -6607,7 +6993,9 @@ static ivas_error renderMcCustomLsToBinauralRoom( float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; int8_t combinedOrientationEnabled; +#ifndef API_5MS int16_t subframe_idx; +#endif push_wmops( "renderMcCustomLsToBinauralRoom" ); @@ -6622,6 +7010,13 @@ static ivas_error renderMcCustomLsToBinauralRoom( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + /* fix compilin only, ToDo adapt renderer to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) @@ -6630,6 +7025,7 @@ static ivas_error renderMcCustomLsToBinauralRoom( break; } } +#endif } /* apply rotation */ @@ -6639,7 +7035,13 @@ static ivas_error renderMcCustomLsToBinauralRoom( tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) ); set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels ); - if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, + if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, +#ifdef LIB_REND_API_5MS + &mcInput->customLsInput, +#else + mcInput->customLsInput, +#endif + mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK ) { @@ -6669,11 +7071,15 @@ static ivas_error renderMcCustomLsToBinauralRoom( /* call CREND */ if ( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, AUDIO_CONFIG_7_1_4, getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *mcInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 #endif - ) ) != IVAS_ERR_OK ) + ) ) != IVAS_ERR_OK ) { return error; } @@ -6796,6 +7202,16 @@ static ivas_error renderMcToSplitBinaural( combinedOrientationDataLocal = *pCombinedOrientationDataLocal; if ( pMultiBinPoseData->poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = combinedOrientationDataLocal.Quaternion; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + combinedOrientationDataLocal.Rmat[i][j] = combinedOrientationDataLocal.Rmat[i][j]; + } + } +#else for ( sf = 1; sf < RENDERER_HEAD_POSITIONS_PER_FRAME; ++sf ) { combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0]; @@ -6807,12 +7223,25 @@ static ivas_error renderMcToSplitBinaural( } } } +#endif } for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ ) { /* Update head positions */ +#ifdef API_5MS + IVAS_QUATERNION Quaternion_orig, Quaternion_abs; + Quaternion_orig = combinedOrientationDataLocal.Quaternion; + Quaternion_abs.w = -3.0f; + Quat2EulerDegree( combinedOrientationDataLocal.Quaternion, &Quaternion_abs.z, &Quaternion_abs.y, &Quaternion_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ + + Quaternion_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + Quaternion_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + Quaternion_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + combinedOrientationDataLocal.Quaternion = Quaternion_abs; + QuatToRotMat( combinedOrientationDataLocal.Quaternion, combinedOrientationDataLocal.Rmat ); +#else IVAS_QUATERNION Quaternions_orig[RENDERER_HEAD_POSITIONS_PER_FRAME], Quaternions_abs; for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { @@ -6826,6 +7255,7 @@ static ivas_error renderMcToSplitBinaural( combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs; QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] ); } +#endif if ( inConfig == IVAS_REND_AUDIO_CONFIG_LS_CUSTOM || inConfig == IVAS_REND_AUDIO_CONFIG_5_1 || inConfig == IVAS_REND_AUDIO_CONFIG_7_1 ) { @@ -6881,7 +7311,11 @@ static ivas_error renderMcToSplitBinaural( pCombinedOrientationDataLocal = &combinedOrientationDataLocal; if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, +#ifdef API_5MS + &mcInput->customLsInput, +#else mcInput->customLsInput, +#endif mcInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, mcInput->rot_gains_prev, @@ -6903,6 +7337,9 @@ static ivas_error renderMcToSplitBinaural( NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate, +#ifdef API_5MS + 4, +#endif pos_idx ) ) != IVAS_ERR_OK ) { return error; @@ -6917,10 +7354,14 @@ static ivas_error renderMcToSplitBinaural( } /* restore original headrotation data */ +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = Quaternion_orig; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i]; } +#endif } /* TODO tmu : needs delay compensation */ @@ -6951,8 +7392,7 @@ static ivas_error renderInputMc( if ( mcInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) { - /* Mismatch between the number of input samples vs number of requested output samples - currently not allowed */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } mcInput->base.numNewSamplesPerChannel = 0; @@ -7124,7 +7564,7 @@ static ivas_error renderSplitBinauralWithPostRot( float Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX]; ivas_error error; - IVAS_QUATERNION QuaternionsPost[MAX_PARAM_SPATIAL_SUBFRAMES]; + IVAS_QUATERNION QuaternionsPost[MAX_PARAM_SPATIAL_SUBFRAMES]; /* TODO(splitrend): remove subframes */ int16_t sf_idx; ivas_split_rend_bits_t bits; float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k]; @@ -7167,7 +7607,11 @@ static ivas_error renderSplitBinauralWithPostRot( for ( sf_idx = 0; sf_idx < MAX_PARAM_SPATIAL_SUBFRAMES; sf_idx++ ) { +#ifdef API_5MS + QuaternionsPost[sf_idx] = pCombinedOrientationData->Quaternion; +#else QuaternionsPost[sf_idx] = ivas_split_rend_get_sf_rot_data( pCombinedOrientationData->Quaternions, sf_idx ); +#endif } if ( !SplitRendBFI ) @@ -7310,6 +7754,16 @@ static ivas_error renderSbaToMultiBinaural( combinedOrientationDataLocal = *pCombinedOrientationDataLocal; if ( pMultiBinPoseData->poseCorrectionMode == IVAS_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) { +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = combinedOrientationDataLocal.Quaternion; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + combinedOrientationDataLocal.Rmat[i][j] = combinedOrientationDataLocal.Rmat[i][j]; + } + } +#else for ( sf = 1; sf < RENDERER_HEAD_POSITIONS_PER_FRAME; sf++ ) { combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0]; @@ -7321,6 +7775,7 @@ static ivas_error renderSbaToMultiBinaural( } } } +#endif } tmpRotBuffer = sbaInput->base.inputBuffer; @@ -7328,6 +7783,18 @@ static ivas_error renderSbaToMultiBinaural( for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ ) { +#ifdef API_5MS + IVAS_QUATERNION Quaternion_orig, Quaternion_abs; + Quaternion_orig = combinedOrientationDataLocal.Quaternion; + Quaternion_abs.w = -3.0f; + Quat2EulerDegree( combinedOrientationDataLocal.Quaternion, &Quaternion_abs.z, &Quaternion_abs.y, &Quaternion_abs.x ); /*order in Quat2Euler seems to be reversed ?*/ + + Quaternion_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0]; + Quaternion_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1]; + Quaternion_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2]; + combinedOrientationDataLocal.Quaternion = Quaternion_abs; + QuatToRotMat( combinedOrientationDataLocal.Quaternion, combinedOrientationDataLocal.Rmat ); +#else IVAS_QUATERNION Quaternions_orig[RENDERER_HEAD_POSITIONS_PER_FRAME], Quaternions_abs; for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { @@ -7341,6 +7808,7 @@ static ivas_error renderSbaToMultiBinaural( combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs; QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] ); } +#endif /* copy input for in-place rotation */ @@ -7363,15 +7831,22 @@ static ivas_error renderSbaToMultiBinaural( NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate, +#ifdef API_5MS + 4, +#endif pos_idx ) ) != IVAS_ERR_OK ) { return error; } +#ifdef API_5MS + combinedOrientationDataLocal.Quaternion = Quaternion_orig; +#else for ( i = 0; i < RENDERER_HEAD_POSITIONS_PER_FRAME; i++ ) { combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i]; } +#endif /* move to output */ for ( i = 0; i < BINAURAL_CHANNELS; i++ ) @@ -7461,7 +7936,9 @@ static ivas_error renderSbaToBinaural( int16_t i; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; int8_t combinedOrientationEnabled; +#ifndef API_5MS int16_t subframe_idx; +#endif push_wmops( "renderSbaToBinaural" ); @@ -7484,6 +7961,13 @@ static ivas_error renderSbaToBinaural( p_tmpCrendBuffer[i] = tmpCrendBuffer[i]; } +#ifdef API_5MS + /* fix compiling only, ToDo ext renderer needs to adapted to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData; combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) @@ -7497,6 +7981,7 @@ static ivas_error renderSbaToBinaural( } } } +#endif /* apply rotation */ if ( combinedOrientationEnabled ) @@ -7533,6 +8018,10 @@ static ivas_error renderSbaToBinaural( /* call CREND */ if ( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, getIvasAudioConfigFromRendAudioConfig( sbaInput->base.inConfig ), getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 @@ -7565,7 +8054,9 @@ static ivas_error renderSbaToBinauralRoom( float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS]; const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData; int8_t combinedOrientationEnabled; +#ifndef API_5MS int16_t subframe_idx; +#endif tmpRotBuffer = outAudio; /* avoid compilation warning */ @@ -7580,6 +8071,13 @@ static ivas_error renderSbaToBinauralRoom( combinedOrientationEnabled = 0; if ( hCombinedOrientationData != NULL ) { +#ifdef API_5MS + /* fix compiling only, ToDo ext renderer needs to adapted to 5ms */ + if ( ( *hCombinedOrientationData )->enableCombinedOrientation != 0 ) + { + combinedOrientationEnabled = 1; + } +#else for ( subframe_idx = 0; subframe_idx < MAX_PARAM_SPATIAL_SUBFRAMES; subframe_idx++ ) { if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 ) @@ -7588,6 +8086,7 @@ static ivas_error renderSbaToBinauralRoom( break; } } +#endif } /* apply rotation */ @@ -7635,11 +8134,15 @@ static ivas_error renderSbaToBinauralRoom( /* call CREND */ if ( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, AUDIO_CONFIG_7_1_4, getIvasAudioConfigFromRendAudioConfig( outConfig ), NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , 0 #endif - ) ) != IVAS_ERR_OK ) + ) ) != IVAS_ERR_OK ) { return error; } @@ -7733,8 +8236,7 @@ static ivas_error renderInputSba( if ( sbaInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) #endif { - /* Mismatch between the number of input samples vs number of requested output samples - currently not allowed */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } sbaInput->base.numNewSamplesPerChannel = 0; @@ -7892,11 +8394,21 @@ static void renderMasaToMc( if ( masaInput->decDummy->renderer_type == RENDERER_STEREO_PARAMETRIC ) { - ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); + ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *masaInput->base.ctx.pOutSampleRate ) +#endif + ); } else { - ivas_dirac_dec( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); + ivas_dirac_dec( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *masaInput->base.ctx.pOutSampleRate ) +#endif + ); } accumulate2dArrayToBuffer( tmpBuffer, &outAudio ); @@ -7913,7 +8425,12 @@ static void renderMasaToSba( copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer ); copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->decDummy->hSpatParamRendCom ); - ivas_dirac_dec( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); + ivas_dirac_dec( masaInput->decDummy, tmpBuffer, masaInput->base.inputBuffer.config.numChannels +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *masaInput->base.ctx.pOutSampleRate ) +#endif + ); accumulate2dArrayToBuffer( tmpBuffer, &outAudio ); @@ -7929,7 +8446,12 @@ static void renderMasaToBinaural( copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer ); copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->decDummy->hSpatParamRendCom ); - ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels ); + ivas_dirac_dec_binaural( masaInput->decDummy, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, masaInput->base.inputBuffer.config.numChannels +#ifdef LIB_REND_API_5MS + , + num_subframes_in_buffer( &outAudio, *masaInput->base.ctx.pOutSampleRate ) +#endif + ); accumulate2dArrayToBuffer( tmpBuffer, &outAudio ); @@ -8080,8 +8602,7 @@ static ivas_error renderInputMasa( if ( masaInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel ) { - /* Mismatch between the number of input samples vs number of requested output samples - currently not allowed */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" ); } masaInput->base.numNewSamplesPerChannel = 0; @@ -8135,7 +8656,9 @@ static ivas_error renderActiveInputsMasa( int16_t i; input_masa *pCurrentInput; ivas_error error; +#ifndef LIB_REND_API_5MS int16_t sf_idx; +#endif for ( i = 0, pCurrentInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pCurrentInput ) { @@ -8147,11 +8670,22 @@ static ivas_error renderActiveInputsMasa( if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL && pCurrentInput->decDummy->hHeadTrackData != NULL ) { +#ifdef LIB_REND_API_5MS + pCurrentInput->decDummy->hHeadTrackData->Quaternion = hIvasRend->headRotData.headPosition; + pCurrentInput->decDummy->hHeadTrackData->Pos = hIvasRend->headRotData.Pos; +#else for ( sf_idx = 0; sf_idx < RENDERER_HEAD_POSITIONS_PER_FRAME; ++sf_idx ) { +#ifdef API_5MS + /* fix compilation only, ToDo adapt ext renderer to 5ms */ + pCurrentInput->decDummy->hHeadTrackData->Quaternion = hIvasRend->headRotData.headPositions[sf_idx]; + pCurrentInput->decDummy->hHeadTrackData->Pos = hIvasRend->headRotData.Pos[sf_idx]; +#else pCurrentInput->decDummy->hHeadTrackData->Quaternions[sf_idx] = hIvasRend->headRotData.headPositions[sf_idx]; pCurrentInput->decDummy->hHeadTrackData->Pos[sf_idx] = hIvasRend->headRotData.Pos[sf_idx]; +#endif } +#endif } if ( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK ) @@ -8389,8 +8923,7 @@ ivas_error IVAS_REND_GetSamples( outAudio.config.numSamplesPerChannel * 1000 != BINAURAL_RENDERING_FRAME_SIZE_MS * hIvasRend->sampleRateOut ) #endif { - /* Binaural rendering requires specific frame size */ - return IVAS_ERR_INVALID_BUFFER_SIZE; + return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" ); } /* Check that there is allowed configuration for MASA format output */ @@ -8525,7 +9058,7 @@ ivas_error IVAS_REND_GetSamples( /* Encode split rendering bitstream */ convertBitsBufferToInternalBitsBuff( *hBits, &bits ); error = ivas_renderMultiBinToSplitBinaural( &hIvasRend->splitRendWrapper, - hIvasRend->headRotData.headPositions, + hIvasRend->headRotData.headPosition, hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec, &bits, diff --git a/lib_rend/lib_rend.h b/lib_rend/lib_rend.h index c86b8bcbf2590d3167be4fbae00ad3922bd19440..0edbd3b4444d898efff1ca3bf7f0ee3187f1a38f 100644 --- a/lib_rend/lib_rend.h +++ b/lib_rend/lib_rend.h @@ -273,14 +273,26 @@ int16_t IVAS_REND_FeedRenderConfig( ivas_error IVAS_REND_SetHeadRotation( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ +#ifdef LIB_REND_API_5MS + const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */ + const IVAS_VECTOR3 Pos /* i : listener positions for next rendering call */ +#else const IVAS_QUATERNION headRot[RENDERER_HEAD_POSITIONS_PER_FRAME], /* i : head orientations for next rendering call */ - const IVAS_VECTOR3 Pos[RENDERER_HEAD_POSITIONS_PER_FRAME] /* i : listener positions for next rendering call */ + const IVAS_VECTOR3 Pos[RENDERER_HEAD_POSITIONS_PER_FRAME] /* i : listener positions for next rendering call */ +#endif #ifdef SPLIT_REND_WITH_HEAD_ROT , IVAS_SPLIT_REND_ROT_AXIS rot_axis #endif ); +#ifdef LIB_REND_API_5MS +/* Head rotation becomes enabled by calling IVAS_REND_SetHeadRotation. Use this to disable. */ +ivas_error IVAS_REND_DisableHeadRotation( + IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */ +); +#endif + ivas_error IVAS_REND_SetOrientationTrackingMode( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ const HEAD_ORIENT_TRK_T orientation_tracking /* i : Head orientation tracking type */ @@ -316,10 +328,17 @@ ivas_error IVAS_REND_SetSplitRendBFI( ivas_error IVAS_REND_SetExternalOrientation( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ IVAS_QUATERNION *orientation, /* i : external orientation data */ +#ifdef LIB_REND_API_5MS + int8_t enableHeadRotation, /* i : flag to enable head rotation for this frame */ + int8_t enableExternalOrientation, /* i : flag to enable external orientation for this frame */ + int8_t enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ + int16_t numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#else int8_t *enableHeadRotation, /* i : flag to enable head rotation for this frame */ int8_t *enableExternalOrientation, /* i : flag to enable external orientation for this frame */ int8_t *enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */ int16_t *numFramesToTargetOrientation /* i : number of frames until target orientation is reached */ +#endif ); ivas_error IVAS_REND_CombineHeadAndExternalOrientation( @@ -328,7 +347,7 @@ ivas_error IVAS_REND_CombineHeadAndExternalOrientation( ivas_error IVAS_REND_GetCombinedOrientation( IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */ - IVAS_QUATERNION *pRotation /* i/o: Quaternion pointer processed orientation */ + IVAS_QUATERNION *pOrientation /* i/o: Quaternion pointer processed orientation */ ); ivas_error IVAS_REND_GetMasaMetadata( diff --git a/scripts/razel/ivas_files_map_for_razel.py b/scripts/razel/ivas_files_map_for_razel.py new file mode 100644 index 0000000000000000000000000000000000000000..0939b0b53b26ea74b4bc20e67f90d715218f2547 --- /dev/null +++ b/scripts/razel/ivas_files_map_for_razel.py @@ -0,0 +1,82 @@ +from typing import Optional + +from ivas_razel_runner.include.core import ( + AudioConfig, + AudioFormat, + AudioSampleType, + CustomSpeakerLayoutFile, + File, + Files, + SceneDescriptionFile, + WavFile, +) +from ivas_razel_runner.include.ivas_rend import IvasRendInputFile + + +def in_file_for_audio_config(config: AudioConfig | SceneDescriptionFile) -> IvasRendInputFile: + if config == AudioFormat.MONO: + return WavFile("scripts/testv/stv48c.wav", True, 48000, 1, AudioSampleType.INT16) + if config == AudioFormat.STEREO: + return WavFile("scripts/testv/stvST48c.wav", True, 48000, 2, AudioSampleType.INT16) + if config == AudioFormat.ISM1: + return WavFile("scripts/testv/stv1ISM48s.wav", True, 48000, 1, AudioSampleType.INT16) + if config == AudioFormat.ISM2: + return WavFile("scripts/testv/stv2ISM48s.wav", True, 48000, 2, AudioSampleType.INT16) + if config == AudioFormat.ISM3: + return WavFile("scripts/testv/stv3ISM48s.wav", True, 48000, 3, AudioSampleType.INT16) + if config == AudioFormat.ISM4: + return WavFile("scripts/testv/stv4ISM48s.wav", True, 48000, 4, AudioSampleType.INT16) + if config == AudioFormat.MC_5_1: + return WavFile("scripts/testv/stv51MC48c.wav", True, 48000, 6, AudioSampleType.INT16) + if config == AudioFormat.MC_7_1: + return WavFile("scripts/testv/stv71MC48c.wav", True, 48000, 8, AudioSampleType.INT16) + if config == AudioFormat.MC_5_1_2: + return WavFile("scripts/testv/stv512MC48c.wav", True, 48000, 8, AudioSampleType.INT16) + if config == AudioFormat.MC_5_1_4: + return WavFile("scripts/testv/stv514MC48c.wav", True, 48000, 10, AudioSampleType.INT16) + if config == AudioFormat.MC_7_1_4: + return WavFile("scripts/testv/stv714MC48c.wav", True, 48000, 12, AudioSampleType.INT16) + if config == AudioFormat.FOA: + return WavFile("scripts/testv/stvFOA48c.wav", True, 48000, 4, AudioSampleType.INT16) + if config == AudioFormat.HOA2: + return WavFile("scripts/testv/stv2OA48c.wav", True, 48000, 9, AudioSampleType.INT16) + if config == AudioFormat.HOA3: + return WavFile("scripts/testv/stv3OA48c.wav", True, 48000, 16, AudioSampleType.INT16) + if config == AudioFormat.MASA1: + return WavFile("scripts/testv/stv2MASA1TC48c.wav", True, 48000, 1, AudioSampleType.INT16) + if config == AudioFormat.MASA2: + return WavFile("scripts/testv/stv2MASA2TC48c.wav", True, 48000, 2, AudioSampleType.INT16) + if isinstance(config, SceneDescriptionFile): + return config + if isinstance(config, CustomSpeakerLayoutFile): + # Assume test file is 5_1 for now + assert config.num_channels == AudioFormat.MC_5_1.num_channels + return WavFile("scripts/testv/stv51MC48c.wav", True, 48000, 6, AudioSampleType.INT16) + + raise RuntimeError(f"No input file for audio config {config}") + + +def md_files_for_audio_config(config: AudioConfig | SceneDescriptionFile) -> Optional[Files]: + if config == AudioFormat.ISM1: + return [File("scripts/testv/stvISM1.csv", True)] + if config == AudioFormat.ISM2: + return [File("scripts/testv/stvISM1.csv", True), File("scripts/testv/stvISM2.csv", True)] + if config == AudioFormat.ISM3: + return [ + File("scripts/testv/stvISM1.csv", True), + File("scripts/testv/stvISM2.csv", True), + File("scripts/testv/stvISM3.csv", True), + ] + if config == AudioFormat.ISM4: + return [ + File("scripts/testv/stvISM1.csv", True), + File("scripts/testv/stvISM2.csv", True), + File("scripts/testv/stvISM3.csv", True), + File("scripts/testv/stvISM4.csv", True), + ] + if config == AudioFormat.MASA1: + return [File("scripts/testv/stv2MASA1TC48c.met", True)] + if config == AudioFormat.MASA2: + return [File("scripts/testv/stv2MASA2TC48c.met", True)] + + return None diff --git a/scripts/razel/ivas_razel_runner b/scripts/razel/ivas_razel_runner new file mode 160000 index 0000000000000000000000000000000000000000..9676b98c617410b94bbb61feb4fb2dc778887255 --- /dev/null +++ b/scripts/razel/ivas_razel_runner @@ -0,0 +1 @@ +Subproject commit 9676b98c617410b94bbb61feb4fb2dc778887255 diff --git a/scripts/razel/test_renderer_razel.py b/scripts/razel/test_renderer_razel.py new file mode 100755 index 0000000000000000000000000000000000000000..4a61dcfa579126c3855dd62f9f0fa3ff642441ea --- /dev/null +++ b/scripts/razel/test_renderer_razel.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 + +import itertools +import logging +from pathlib import Path + +from ivas_files_map_for_razel import in_file_for_audio_config, md_files_for_audio_config +from ivas_razel_runner.include.core import ( + AudioFile, + AudioFormat, + CustomSpeakerLayoutFile, + File, + FileFormat, + SceneDescriptionFile, + WavDiffArgs, + WavFile, +) +from ivas_razel_runner.include.ivas_rend import IvasRend, IvasRendConfig, UnsupportedConfigWarning +from ivas_razel_runner.include.sox import Sox +from razel import Razel + +####################################################### + +BINAURAL_FORMATS = [ + AudioFormat.BINAURAL, + AudioFormat.BINAURAL_ROOM_IR, + AudioFormat.BINAURAL_ROOM_REVERB, +] +DEFAULT_CUSTOM_SPEAKER_LAYOUT = CustomSpeakerLayoutFile("scripts/ls_layouts/cicp6.txt", 6) +DEFAULT_SCENE_DESCRIPTION_FILE = SceneDescriptionFile("_dev/in/scene_ism2.txt", in_file_for_audio_config(AudioFormat.ISM2)) # type: ignore + +####################################################### + +INPUT_FORMATS = IvasRend.get_valid_in_audio_configs(DEFAULT_CUSTOM_SPEAKER_LAYOUT, DEFAULT_SCENE_DESCRIPTION_FILE) +OUTPUT_FORMATS = IvasRend.get_valid_out_audio_configs(DEFAULT_CUSTOM_SPEAKER_LAYOUT) +HEAD_ROTATION_FILES = [File("scripts/testv/headrot_case00_3000_q.csv", True), None] +SAMPLING_RATES = [48000] # TODO(sgi): use others + +####################################################### + +KNOWN_BROKEN_BASELINE_CONFIGS = [ + lambda config: config.in_audio_config == AudioFormat.MASA1, + lambda config: isinstance(config.in_audio_config, SceneDescriptionFile), + lambda config: config.in_audio_config == AudioFormat.MASA2 + and isinstance(config.out_audio_config, CustomSpeakerLayoutFile), + lambda config: config.in_audio_config == AudioFormat.MASA2 + and config.out_audio_config in [AudioFormat.BINAURAL_ROOM_IR, AudioFormat.BINAURAL_ROOM_REVERB], +] +KNOWN_CLIPPING_CONFIGS = [ + lambda config: config.in_audio_config + in [AudioFormat.MC_5_1_2, AudioFormat.MC_5_1_4, AudioFormat.MC_5_1, AudioFormat.MC_7_1_4, AudioFormat.MC_7_1] + and config.out_audio_config in [AudioFormat.MONO, AudioFormat.FOA, AudioFormat.HOA2, AudioFormat.HOA3], + lambda config: isinstance(config.in_audio_config, CustomSpeakerLayoutFile) + and config.out_audio_config + in [AudioFormat.MONO, AudioFormat.STEREO, AudioFormat.FOA, AudioFormat.HOA2, AudioFormat.HOA3], + lambda config: config.in_audio_config + in [ + AudioFormat.MC_5_1, + AudioFormat.MC_5_1_2, + AudioFormat.MC_5_1_4, + AudioFormat.MC_7_1, + AudioFormat.MC_7_1_4, + AudioFormat.FOA, + AudioFormat.HOA2, + AudioFormat.HOA3, + ] + and config.out_audio_config in BINAURAL_FORMATS, +] +NON_BE_TO_REF_WITH_5MS_FRAMING = [ + lambda config: config.in_audio_config + in [ + AudioFormat.ISM1, + AudioFormat.ISM2, + AudioFormat.ISM3, + AudioFormat.ISM4, + ] + and config.out_audio_config != AudioFormat.MONO, + lambda config: config.in_audio_config + in [ + AudioFormat.MASA1, + AudioFormat.MASA2, + ], +] +NON_BE_TO_REF_WITH_20MS_FRAMING = [ + lambda config: config.out_audio_config in BINAURAL_FORMATS and config.head_rotation is not None, +] + +####################################################### + + +def main(): + root_workspace = Path(__file__).parent / ".." / ".." + Razel.init(str(root_workspace)) + logging.basicConfig(level=logging.INFO) + + rend_cut = IvasRend(str(root_workspace / "IVAS_rend")) + rend_ref = IvasRend(str(root_workspace / "IVAS_rend_ref_5ms")) + sox = Sox("sox") + AudioFile.set_audio_conversion_tool(sox) + + # Define exceptional configs - order matters here! + rend_ref.add_support_check_for_nonstandard_configs(match_broken_config) + rend_cut.add_support_check_for_nonstandard_configs(match_broken_config) + rend_ref.add_support_check_for_nonstandard_configs( + # Reference can do binaural rendering with 20 ms frames + lambda config: config.out_audio_config in BINAURAL_FORMATS + and config.in_audio_config not in [AudioFormat.MONO, AudioFormat.STEREO] + and not config.framing_5ms + ) + + for in_format, out_format, head_rotation_file in itertools.product( + INPUT_FORMATS, OUTPUT_FORMATS, HEAD_ROTATION_FILES + ): + in_file = in_file_for_audio_config(in_format) + md_files = md_files_for_audio_config(in_format) + config = IvasRendConfig(in_format, out_format, md_files, head_rotation=head_rotation_file, framing_5ms=False) + + if any(match(config) for match in KNOWN_CLIPPING_CONFIGS): + config.input_gain = 0.2 + + # These files' length is not a multiple of 5ms, which causes different output lengths with 5ms framing on/off + if in_file.basename in ["stvFOA48c.wav", "stv2OA48c.wav", "stv3OA48c.wav"]: + assert isinstance(in_file, WavFile) + in_file = in_file.trim(0, 20) + + # Run REF 20ms + try: + out_20ms_ref = rend_ref.render(in_file, config, FileFormat.WAV) + except UnsupportedConfigWarning as e: + logging.info("%s Skipping %s", e.reason, config) + out_20ms_ref = None + + # Run CUT 20ms + try: + out_20ms_cut = rend_cut.render(in_file, config, FileFormat.WAV) + except UnsupportedConfigWarning as e: + logging.info("%s Skipping %s", e.reason, config) + out_20ms_cut = None + + if out_20ms_ref and out_20ms_cut: + if any(match(config) for match in NON_BE_TO_REF_WITH_20MS_FRAMING): + assert isinstance(out_20ms_cut, WavFile) + out_20ms_cut.should_not_equal(out_20ms_ref) + out_20ms_cut.should_be_similar_to(out_20ms_ref, WavDiffArgs(mld_max=0.01)) + else: + out_20ms_cut.should_equal(out_20ms_ref) + + # Run CUT 5ms + config.framing_5ms = True + try: + out_5ms_cut = rend_cut.render(in_file, config, FileFormat.WAV) + except UnsupportedConfigWarning as e: + logging.info("%s Skipping %s", e.reason, config) + out_5ms_cut = None + + if out_5ms_cut and out_20ms_ref: + if any(match(config) for match in NON_BE_TO_REF_WITH_5MS_FRAMING): + assert isinstance(out_5ms_cut, WavFile) + out_5ms_cut.should_not_equal(out_20ms_ref) + out_5ms_cut.should_be_similar_to( + out_20ms_ref, WavDiffArgs(mld_max=16) + ) # TODO(sgi): also test ISM with no metadata (should be BE) + else: + out_5ms_cut.should_equal(out_20ms_ref) + + Razel.instance().run(["exec", "-k"]) + + +def match_broken_config(config): + if any(match(config) for match in KNOWN_BROKEN_BASELINE_CONFIGS): + raise UnsupportedConfigWarning("Known broken config.") + + return False + + +if __name__ == "__main__": + main() diff --git a/scripts/self_test.py b/scripts/self_test.py index d7118832db57d14fad8db5451230c3ab79ae5de2..321f83419bfc9b370755b3f0063342d880db40b0 100755 --- a/scripts/self_test.py +++ b/scripts/self_test.py @@ -186,6 +186,13 @@ class SelfTest(IvasScriptsCommon.IvasScript): "--dectest", help="Test decoder binary (default:{})".format(default_dec_test), ) + self.parser.add_argument( + "--list_conditions", + "-l", + help="List all comditions in the parameter file", + action="store_true", + default=False, + ) if shutil.which("valgrind"): self.valgrind = [ "valgrind", @@ -858,6 +865,7 @@ class SelfTest(IvasScriptsCommon.IvasScript): # add the detailed results for this condition self.fail_results["detailedResults"].append(result_str) + self.fail_results["failed_modes"].append(mode) self.logger.progress( "Comparing conditions: {}/{} ({} running), {} failed ".format( self.stat["num_tests_done"], @@ -1140,6 +1148,11 @@ class SelfTest(IvasScriptsCommon.IvasScript): self.parse_args() + if self.args["list_conditions"] is True: + run_dict = self.parse_self_test_prm(self.args["test_prm"]) + for mode in run_dict.keys(): + self.logger.console(f"- {run_dict[mode]['cmd']['table_name']}") + return # create/update test vectors (export from SVN server if not existing) svn_action = None if not os.path.exists(TESTV_DIR): @@ -1540,6 +1553,7 @@ class SelfTest(IvasScriptsCommon.IvasScript): "corrupt_test_conditions": {"cnt": 0, "conditions": []}, "diff_nsamples_conditions": {"cnt": 0, "conditions": []}, "detailedResults": [], + "failed_modes":[], } self.run_pesq = self.args["pesq"] failed_ref_conditions = {} @@ -1948,6 +1962,15 @@ class SelfTest(IvasScriptsCommon.IvasScript): for l in r: self.logger.info(l) + self.logger.info("\n\n") + self.logger.info("Summary of all tests") + self.logger.info("---------------------\n") + for mode in run_dict.keys(): + if mode in self.fail_results["failed_modes"]: + self.logger.info(f"[FAIL] {run_dict[mode]['cmd']['table_name']}") + else: + self.logger.info(f"[OK] {run_dict[mode]['cmd']['table_name']}") + if __name__ == "__main__": if sys.version_info[0] < 3 or sys.version_info[1] < 7: diff --git a/tests/renderer/constants.py b/tests/renderer/constants.py index 877a1454c2a425e13477f2a751f4dea23e071d6c..5780ee964b64c11d983255aa2247a3792990b2be 100644 --- a/tests/renderer/constants.py +++ b/tests/renderer/constants.py @@ -200,6 +200,9 @@ HR_TRAJECTORIES_TO_TEST = [ "rotate_yaw_pitch_roll1", ] +""" 5ms framing """ +FRAMING_5MS_TO_TEST = [True, False] + """ Per-testcase xfail SNR thresholds (dB) """ pass_snr = dict() # not relevant for tests anymore, should be deprecated soon _pass_snr = { diff --git a/tests/renderer/test_renderer.py b/tests/renderer/test_renderer.py index c057ff9a02bfecb96dc8a8131ed9b25c28a5da36..958b09f110581e251385cbfec92c752ce44ccbcb 100644 --- a/tests/renderer/test_renderer.py +++ b/tests/renderer/test_renderer.py @@ -35,25 +35,35 @@ from .utils import * @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[2:]) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_AMBI) -def test_ambisonics(test_info, in_fmt, out_fmt): - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ambisonics(test_info, in_fmt, out_fmt, framing_5ms): + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, framing_5ms=framing_5ms) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_AMBI) -def test_ambisonics_binaural_static(test_info, in_fmt, out_fmt): - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ambisonics_binaural_static(test_info, in_fmt, out_fmt, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, framing_5ms=framing_5ms) @pytest.mark.parametrize("trj_file", HR_TRAJECTORIES_TO_TEST) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_AMBI) -def test_ambisonics_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ambisonics_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + run_renderer( in_fmt, out_fmt, test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + framing_5ms=framing_5ms, ) @@ -72,10 +82,12 @@ def test_ambisonics_binaural_headrotation_refrotzero( ref_kwargs={ "name_extension": "refrotzero", "trj_file": HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), "refrot_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), + "framing_5ms": True, }, ) @@ -92,6 +104,7 @@ def test_ambisonics_binaural_headrotation_refrotequal(test_info, in_fmt, out_fmt out_fmt, ref_kwargs={ "name_extension": "refrotequal", + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath( @@ -100,6 +113,7 @@ def test_ambisonics_binaural_headrotation_refrotequal(test_info, in_fmt, out_fmt "refrot_file": HR_TRAJECTORY_DIR.joinpath( "azi_plus_2-ele_plus_2-every-25-rows.csv" ), + "framing_5ms": True, }, ) @@ -121,10 +135,12 @@ def test_ambisonics_binaural_headrotation_refveczero( ref_kwargs={ "name_extension": "refveczero", "trj_file": HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), "refvec_file": HR_TRAJECTORY_DIR.joinpath("const000-Vector3.csv"), + "framing_5ms": True, }, ) @@ -146,6 +162,7 @@ def test_ambisonics_binaural_headrotation_refvecequal(test_info, in_fmt, out_fmt out_fmt, ref_kwargs={ "name_extension": "refvecequal", + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath( @@ -154,6 +171,7 @@ def test_ambisonics_binaural_headrotation_refvecequal(test_info, in_fmt, out_fmt "refvec_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-Vector3.csv" ), + "framing_5ms": True, }, ) @@ -178,12 +196,14 @@ def test_ambisonics_binaural_headrotation_refvec_rotating(test_info, in_fmt, out "trj_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s.csv" ), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), "refvec_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-ccw-Vector3.csv" ), + "framing_5ms": True, }, ) @@ -208,12 +228,14 @@ def test_ambisonics_binaural_headrotation_refvec_rotating_fixed_pos_offset( "trj_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-ccw.csv" ), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), "refvec_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-fixed-pos-offset-Vector3.csv" ), + "framing_5ms": True, }, ) @@ -238,10 +260,12 @@ def test_ambisonics_binaural_headrotation_refveclev_vs_refvec( "refveclev_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-Vector3.csv" ), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), "refvec_file": HR_TRAJECTORY_DIR.joinpath("full-circle-4s-Vector3.csv"), + "framing_5ms": True, }, ) @@ -251,25 +275,32 @@ def test_ambisonics_binaural_headrotation_refveclev_vs_refvec( @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[2:]) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MC) -def test_multichannel(test_info, in_fmt, out_fmt): - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_multichannel(test_info, in_fmt, out_fmt, framing_5ms): + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, framing_5ms=framing_5ms) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MC) -def test_multichannel_binaural_static(test_info, in_fmt, out_fmt): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_multichannel_binaural_static(test_info, in_fmt, out_fmt, framing_5ms): if in_fmt in ["MONO", "STEREO"]: pytest.skip("MONO or STEREO to Binaural rendering unsupported") + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name) + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, framing_5ms=framing_5ms) @pytest.mark.parametrize("trj_file", HR_TRAJECTORIES_TO_TEST) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MC) -def test_multichannel_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_multichannel_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file, framing_5ms): if in_fmt in ["MONO", "STEREO"]: pytest.skip("MONO or STEREO to Binaural rendering unsupported") + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") if (in_fmt == "5_1" or in_fmt == "7_1") and out_fmt == "BINAURAL": run_renderer( @@ -277,6 +308,7 @@ def test_multichannel_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file out_fmt, test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + framing_5ms=framing_5ms, ) else: run_renderer( @@ -284,6 +316,7 @@ def test_multichannel_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file out_fmt, test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + framing_5ms=framing_5ms, ) @@ -306,12 +339,14 @@ def test_multichannel_binaural_headrotation_refvec_rotating(test_info, in_fmt, o "trj_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s.csv" ), + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), "refvec_file": HR_TRAJECTORY_DIR.joinpath( "full-circle-with-up-and-down-4s-ccw-Vector3.csv" ), + "framing_5ms": True, }, ) @@ -321,28 +356,37 @@ def test_multichannel_binaural_headrotation_refvec_rotating(test_info, in_fmt, o @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[2:]) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_ISM) -def test_ism(test_info, in_fmt, out_fmt): - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=FORMAT_TO_METADATA_FILES[in_fmt]) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ism(test_info, in_fmt, out_fmt, framing_5ms): + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=FORMAT_TO_METADATA_FILES[in_fmt], framing_5ms=framing_5ms) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_ISM) -def test_ism_binaural_static(test_info, in_fmt, out_fmt): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ism_binaural_static(test_info, in_fmt, out_fmt, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + try: in_meta_files = FORMAT_TO_METADATA_FILES[in_fmt] except: in_meta_files = None if out_fmt == "BINAURAL": - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=in_meta_files) + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=in_meta_files, framing_5ms=framing_5ms) else: - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=in_meta_files) + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=in_meta_files, framing_5ms=framing_5ms) @pytest.mark.parametrize("trj_file", HR_TRAJECTORIES_TO_TEST) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_ISM) -def test_ism_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_ism_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + try: in_meta_files = FORMAT_TO_METADATA_FILES[in_fmt] except: @@ -355,6 +399,7 @@ def test_ism_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file): test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), in_meta_files=in_meta_files, + framing_5ms=framing_5ms, ) else: run_renderer( @@ -363,6 +408,7 @@ def test_ism_binaural_headrotation(test_info, in_fmt, out_fmt, trj_file): test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), in_meta_files=in_meta_files, + framing_5ms=framing_5ms, ) @@ -388,6 +434,7 @@ def test_ism_binaural_headrotation_refvec_rotating(test_info, in_fmt, out_fmt): "full-circle-with-up-and-down-4s.csv" ), "in_meta_files": in_meta_files, + "framing_5ms": True, }, cut_kwargs={ "trj_file": HR_TRAJECTORY_DIR.joinpath("const000.csv"), @@ -395,6 +442,7 @@ def test_ism_binaural_headrotation_refvec_rotating(test_info, in_fmt, out_fmt): "full-circle-with-up-and-down-4s-ccw-Vector3.csv" ), "in_meta_files": in_meta_files, + "framing_5ms": True, }, ) @@ -404,8 +452,9 @@ def test_ism_binaural_headrotation_refvec_rotating(test_info, in_fmt, out_fmt): @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS) @pytest.mark.parametrize("in_fmt", INPUT_FORMATS_MASA) -def test_masa(test_info, in_fmt, out_fmt): - run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=FORMAT_TO_METADATA_FILES[in_fmt]) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_masa(test_info, in_fmt, out_fmt, framing_5ms): + run_renderer(in_fmt, out_fmt, test_case_name=test_info.node.name, in_meta_files=FORMAT_TO_METADATA_FILES[in_fmt], framing_5ms=framing_5ms) """ Custom loudspeaker layouts """ @@ -413,8 +462,9 @@ def test_masa(test_info, in_fmt, out_fmt): @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[2:]) @pytest.mark.parametrize("in_layout", CUSTOM_LS_TO_TEST) -def test_custom_ls_input(test_info, in_layout, out_fmt): - run_renderer(CUSTOM_LAYOUT_DIR.joinpath(f"{in_layout}.txt"), out_fmt, test_case_name=test_info.node.name) +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_custom_ls_input(test_info, in_layout, out_fmt, framing_5ms): + run_renderer(CUSTOM_LAYOUT_DIR.joinpath(f"{in_layout}.txt"), out_fmt, test_case_name=test_info.node.name, framing_5ms=framing_5ms) @pytest.mark.parametrize("out_fmt", CUSTOM_LS_TO_TEST) @@ -439,10 +489,15 @@ def test_custom_ls_input_output(test_info, in_fmt, out_fmt): @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_layout", CUSTOM_LS_TO_TEST) -def test_custom_ls_input_binaural(test_info, in_layout, out_fmt): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_custom_ls_input_binaural(test_info, in_layout, out_fmt, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + run_renderer( CUSTOM_LAYOUT_DIR.joinpath(f"{in_layout}.txt"), out_fmt, + framing_5ms=framing_5ms, test_case_name=test_info.node.name, ) @@ -450,12 +505,17 @@ def test_custom_ls_input_binaural(test_info, in_layout, out_fmt): @pytest.mark.parametrize("trj_file", HR_TRAJECTORIES_TO_TEST) @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS_BINAURAL) @pytest.mark.parametrize("in_layout", CUSTOM_LS_TO_TEST) -def test_custom_ls_input_binaural_headrotation(test_info, in_layout, out_fmt, trj_file): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_custom_ls_input_binaural_headrotation(test_info, in_layout, out_fmt, trj_file, framing_5ms): + if not framing_5ms: + pytest.xfail("Binaural output currently only supported with 5ms framing") + run_renderer( CUSTOM_LAYOUT_DIR.joinpath(f"{in_layout}.txt"), out_fmt, test_case_name=test_info.node.name, trj_file=HR_TRAJECTORY_DIR.joinpath(f"{trj_file}.csv"), + framing_5ms=framing_5ms, ) @@ -464,12 +524,14 @@ def test_custom_ls_input_binaural_headrotation(test_info, in_layout, out_fmt, tr @pytest.mark.parametrize("out_fmt", OUTPUT_FORMATS[2:]) @pytest.mark.parametrize("in_fmt", METADATA_SCENES_TO_TEST) -def test_metadata(test_info, in_fmt, out_fmt): +@pytest.mark.parametrize("framing_5ms", FRAMING_5MS_TO_TEST) +def test_metadata(test_info, in_fmt, out_fmt, framing_5ms): run_renderer( "META", out_fmt, test_case_name=test_info.node.name, metadata_input=TEST_VECTOR_DIR.joinpath(f"{in_fmt}.txt"), + framing_5ms=framing_5ms, ) diff --git a/tests/renderer/utils.py b/tests/renderer/utils.py index cf4bbd1bdf2ef98bf3b6b07e2a935c7e5c551ec6..d23c094bb8a5b13b732f43c5f7a271d8c5e4f45d 100644 --- a/tests/renderer/utils.py +++ b/tests/renderer/utils.py @@ -114,6 +114,7 @@ def run_renderer( output_path_base: str = OUTPUT_PATH_CUT, binary_suffix: str = "", is_comparetest: Optional[bool] = False, + framing_5ms: Optional[bool] = False, test_case_name: Optional[str] = None, ) -> Tuple[np.ndarray, int]: """CuT creation with standalone renderer""" @@ -142,6 +143,10 @@ def run_renderer( else: config_name = "" + if framing_5ms: + framing_name = "_5ms_framing" + else: + framing_name = "" if not isinstance(out_fmt, str): @@ -166,7 +171,7 @@ def run_renderer( out_file = str( output_path_base.joinpath( - f"{in_name}_to_{out_name}{trj_name}{non_diegetic_pan}{refrot_name}{refvec_name}{refveclev_name}{config_name}{name_extension}.wav" + f"{in_name}_to_{out_name}{trj_name}{non_diegetic_pan}{refrot_name}{refvec_name}{refveclev_name}{config_name}{framing_name}{name_extension}.wav" ) ) @@ -201,6 +206,9 @@ def run_renderer( if config_file is not None: cmd.extend(["-rc", str(config_file)]) + if framing_5ms: + cmd.extend(["-fr5"]) + # Set env variables for UBSAN env = os.environ.copy() if test_case_name and "UBSAN_OPTIONS" in env.keys():